| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/31 03:56 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"WLAN",
"WLAN_VENDOR_MEDIATEK",
"MAC80211",
"MT7925E",
"MT7925U",
"MT7925_COMMON",
"DEBUG_FS"
],
"FocusSymbols": [
"mt792x_stats",
"mt792x_mcu_get_stat",
"mt7925_mcu_get_mib_info",
"mt7925_mcu_get_link_quality",
"mt792x_mcu_get_wtbl_rate",
"mt7925_print_last_tx_rate",
"mt7925_get_ap_sta_rec_idx",
"mt7925_wtbl_get_sgi",
"mt7925_wtbl_get_ldpc"
],
"KMSANReasoning": "The patch adds debugfs statistics reporting and MCU query helpers for the mt7925 driver (including station statistics, MIB counters, link quality, and auto-rate table dumping).\n\nEvaluation of KMSAN vs KASAN applicability:\n1. Memory Initialization:\n - Heap allocations use kzalloc() (e.g., stats buffer and MIB request buffer).\n - Stack request structures (mt7925_sta_stats_req, mt7925_wtbl_rate_req, mt7925_lq_req) are initialized using C designated initializers, ensuring all omitted fields and padding are zeroed.\n - Stack arrays such as mib_values are explicitly zeroed via memset() at the entry of mt7925_mcu_get_mib_info().\n - Stack struct wtbl_rate is only read if mt792x_mcu_get_wtbl_rate() returns 0 (which copies the full struct from firmware response skb), guarded by the boolean flag wtbl_rate_valid.\n2. User-Space Exposure:\n - Output to user space is handled exclusively through seq_printf/seq_puts via debugfs seq_file entries (converting data to formatted ASCII strings). There are no raw binary structure copies or memory leaks to user space (no copy_to_user or raw netlink/ioctl transfers).\n3. Any potential bugs related to MCU skb parsing or array indices are bounds/memory corruption issues covered by standard KASAN.\n\nBecause no uninitialized memory reads or info-leaks are introduced, a dedicated KMSAN session is not required.",
"NeedsKMSAN": false,
"Reasoning": "The patch adds debugfs statistics support and associated MCU querying and TLV parsing logic (STA stats, MIB counters, link quality, WTBL auto-rate table, TX vector decode) for MediaTek MT7925 devices. These code paths contain parsing and formatting logic reachable via debugfs and USB device emulation.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/31 03:56 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit d28e1a6c65afcbfa8b3c17b2f361b8ed61e44efc\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Aug 31 03:56:29 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h\nindex 0ededa569e9a5..bf0f105c786e6 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h\n+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h\n@@ -1483,6 +1483,179 @@ enum {\n \tMT_NIC_CAP_EML_CAP = 0x22,\n };\n \n+enum {\n+\tUNI_CMD_ID_STATISTICS_BASIC = 0,\n+\tUNI_CMD_ID_STATISTICS_LINK_QUALITY = 1,\n+\tUNI_CMD_ID_STATISTICS_STA = 2,\n+\tUNI_CMD_ID_STATISTICS_BUG_REPORT = 3,\n+\tUNI_CMD_ID_STATISTICS_TX_STATS = 4,\n+\tUNI_CMD_ID_STATISTICS_ALL_STATS = 5,\n+\tUNI_CMD_ID_STATISTICS_EML_STATS = 6,\n+\tUNI_CMD_ID_STATISTICS_REGULAR_STATS = 7,\n+\tUNI_CMD_ID_STATISTICS_BSS_LINK_QUALITY = 8,\n+\tUNI_CMD_ID_STATISTICS_ML_CHNL_COND = 9,\n+\tUNI_CMD_ID_STATISTICS_WTBL = 10,\n+\tUNI_CMD_ID_STATISTICS_LINK_LAYER_STATS = 128,\n+\tUNI_CMD_ID_STATISTICS_PPDU_LATENCY = 129,\n+\tUNI_CMD_ID_STATISTICS_CURRENT_TX_RATE = 130,\n+\tUNI_CMD_ID_STATISTICS_SET_TX_BITRATE_MONITOR = 131,\n+\tUNI_CMD_ID_STATISTICS_GET_PREDICT_TX_BITRATE = 132,\n+\tUNI_CMD_ID_STATISTICS_SET_ATPS_TYPE_RATE_MODE = 133,\n+\tUNI_CMD_ID_STATISTICS_SET_BEACON_REPORT = 134,\n+\tUNI_CMD_ID_STATISTICS_BSS_CURRENT_TX_RATE = 135,\n+\tUNI_CMD_ID_STATISTICS_GET_BSS_PREDICT_TX_BITRATE = 136,\n+\tUNI_CMD_ID_STATISTICS_MAX_NUM\n+};\n+\n+enum mt7925_mib_counter {\n+\tUNI_CMD_MIB_CNT_RX_FCS_ERR = 0,\n+\tUNI_CMD_MIB_CNT_RX_FIFO_OVERFLOW = 1,\n+\tUNI_CMD_MIB_CNT_RX_MPDU = 2,\n+\tUNI_CMD_MIB_CNT_AMPDU_RX_COUNT = 3,\n+\tUNI_CMD_MIB_CNT_RX_TOTAL_BYTE = 4,\n+\tUNI_CMD_MIB_CNT_RX_VALID_AMPDU_SF = 5,\n+\tUNI_CMD_MIB_CNT_RX_VALID_BYTE = 6,\n+\tUNI_CMD_MIB_CNT_CHANNEL_IDLE = 7,\n+\tUNI_CMD_MIB_CNT_VEC_DROP = 8,\n+\tUNI_CMD_MIB_CNT_DELIMITER_FAIL = 9,\n+\tUNI_CMD_MIB_CNT_VEC_MISMATCH = 10,\n+\tUNI_CMD_MIB_CNT_MDRDY = 11,\n+\tUNI_CMD_MIB_CNT_RX_CCK_MDRDY_TIME = 12,\n+\tUNI_CMD_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME = 13,\n+\tUNI_CMD_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME = 14,\n+\tUNI_CMD_MIB_CNT_PF_DROP = 15,\n+\tUNI_CMD_MIB_CNT_LEN_MISMATCH = 16,\n+\tUNI_CMD_MIB_CNT_P_CCA_TIME = 17,\n+\tUNI_CMD_MIB_CNT_S_CCA_TIME = 18,\n+\tUNI_CMD_MIB_CNT_CCA_NAV_TX_TIME = 19,\n+\tUNI_CMD_MIB_CNT_P_ED_TIME = 20,\n+\tUNI_CMD_MIB_CNT_BCN_TX = 21,\n+\tUNI_CMD_MIB_CNT_TX_BW_20MHZ = 22,\n+\tUNI_CMD_MIB_CNT_TX_BW_40MHZ = 23,\n+\tUNI_CMD_MIB_CNT_TX_BW_80MHZ = 24,\n+\tUNI_CMD_MIB_CNT_TX_BW_160MHZ = 25,\n+\tUNI_CMD_RMAC_CNT_OBSS_AIRTIME = 26,\n+\tUNI_CMD_RMAC_CNT_NONWIFI_AIRTIME = 27,\n+\tUNI_CMD_MIB_CNT_TX_DUR_CNT = 28,\n+\tUNI_CMD_MIB_CNT_RX_DUR_CNT = 29,\n+\tUNI_CMD_MIB_CNT_BA_CNT = 30,\n+\tUNI_CMD_MIB_CNT_MAC2PHY_TX_TIME = 31,\n+\tUNI_CMD_MIB_CNT_RX_OUT_OF_RANGE_COUNT = 32,\n+\tUNI_CMD_MIB_CNT_IBF_TX = 33,\n+\tUNI_CMD_MIB_CNT_EBF_TX = 34,\n+\tUNI_CMD_MIB_CNT_MUBF_TX = 35,\n+\tUNI_CMD_MIB_CNT_RX_BF_VHTFBK = 36,\n+\tUNI_CMD_MIB_CNT_RX_BF_HTFBK = 37,\n+\tUNI_CMD_MIB_CNT_RX_BF_HEFBK = 38,\n+\tUNI_CMD_MIB_CNT_BFEE_TXFBK_BFPOLL_TRI = 39,\n+\tUNI_CMD_MIB_CNT_BFEE_TXFBK_TRI = 40,\n+\tUNI_CMD_MIB_CNT_BFEE_RX_FBKCQI = 41,\n+\tUNI_CMD_MIB_CNT_BFEE_RX_NDP = 42,\n+\tUNI_CMD_MIB_CNT_RX_BF_IBF_UPT = 43,\n+\tUNI_CMD_MIB_CNT_RX_BF_EBF_UPT = 44,\n+\tUNI_CMD_MIB_CNT_BFEE_SP_ABORT = 45,\n+\tUNI_CMD_MIB_CNT_BFEE_TB_LEN_ERR = 46,\n+\tUNI_CMD_MIB_CNT_BFEE_TXFBK_MUTE = 47,\n+\tUNI_CMD_MIB_CNT_BFEE_TMAC_ABORT = 48,\n+\tUNI_CMD_MIB_CNT_BFEE_TXFBK_CPL = 49,\n+\tUNI_CMD_MIB_CNT_BFEE_COANT_BLKTX = 50,\n+\tUNI_CMD_MIB_CNT_BFEE_FBK_SEG = 51,\n+\tUNI_CMD_MIB_CNT_NAV_TIME = 52,\n+\tUNI_CMD_MIB_CNT_TX_ABORT_CNT1 = 53,\n+\tUNI_CMD_MIB_CNT_TX_ABORT_CNT0 = 54,\n+\tUNI_CMD_MIB_CNT_TX_ABORT_CNT3 = 55,\n+\tUNI_CMD_MIB_CNT_TX_ABORT_CNT2 = 56,\n+\tUNI_CMD_MIB_CNT_BSS0_RTS_TX_CNT = 57,\n+\tUNI_CMD_MIB_CNT_BSS1_RTS_TX_CNT = 58,\n+\tUNI_CMD_MIB_CNT_BSS2_RTS_TX_CNT = 59,\n+\tUNI_CMD_MIB_CNT_BSS3_RTS_TX_CNT = 60,\n+\tUNI_CMD_MIB_CNT_BSS0_RTS_RETRY = 61,\n+\tUNI_CMD_MIB_CNT_BSS1_RTS_RETRY = 62,\n+\tUNI_CMD_MIB_CNT_BSS2_RTS_RETRY = 63,\n+\tUNI_CMD_MIB_CNT_BSS3_RTS_RETRY = 64,\n+\tUNI_CMD_MIB_CNT_BSS0_BA_MISS = 65,\n+\tUNI_CMD_MIB_CNT_BSS1_BA_MISS = 66,\n+\tUNI_CMD_MIB_CNT_BSS2_BA_MISS = 67,\n+\tUNI_CMD_MIB_CNT_BSS3_BA_MISS = 68,\n+\tUNI_CMD_MIB_CNT_BSS0_ACK_FAIL = 69,\n+\tUNI_CMD_MIB_CNT_BSS1_ACK_FAIL = 70,\n+\tUNI_CMD_MIB_CNT_BSS2_ACK_FAIL = 71,\n+\tUNI_CMD_MIB_CNT_BSS3_ACK_FAIL = 72,\n+\tUNI_CMD_MIB_CNT_BSS0_FRAME_RETRY = 73,\n+\tUNI_CMD_MIB_CNT_BSS1_FRAME_RETRY = 74,\n+\tUNI_CMD_MIB_CNT_BSS2_FRAME_RETRY = 75,\n+\tUNI_CMD_MIB_CNT_BSS3_FRAME_RETRY = 76,\n+\tUNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_2 = 77,\n+\tUNI_CMD_MIB_CNT_BSS1_FRAME_RETRY_2 = 78,\n+\tUNI_CMD_MIB_CNT_BSS2_FRAME_RETRY_2 = 79,\n+\tUNI_CMD_MIB_CNT_BSS3_FRAME_RETRY_2 = 80,\n+\tUNI_CMD_MIB_CNT_RX_A1_SEARCH = 81,\n+\tUNI_CMD_MIB_CNT_RX_DROP_MPDU = 82,\n+\tUNI_CMD_MIB_CNT_RX_UNWANTED = 83,\n+\tUNI_CMD_MIB_CNT_RX_FCS_OK = 84,\n+\tUNI_CMD_MIB_CNT_SU_TX_OK = 85,\n+\tUNI_CMD_MIB_CNT_TX_FULL_BW = 86,\n+\tUNI_CMD_MIB_CNT_TX_AUTO_BW = 87,\n+\tUNI_CMD_MIB_CNT_CCA_SAMPLE_IDLE = 88,\n+\tUNI_CMD_MIB_CNT_CCA_SAMPLE_ACTIVE = 89,\n+\tUNI_CMD_MIB_CNT_CCA_TIME = 90,\n+\tUNI_CMD_MIB_CNT_S_20BW_CCA_TIME = 91,\n+\tUNI_CMD_MIB_CNT_S_40BW_CCA_TIME = 92,\n+\tUNI_CMD_MIB_CNT_S_80BW_CCA_TIME = 93,\n+\tUNI_CMD_MIB_CNT_S_160BW_CCA_TIME = 94,\n+\tUNI_CMD_MIB_CNT_S_P20BW_0_ED_TIME = 95,\n+\tUNI_CMD_MIB_CNT_S_P20BW_1_ED_TIME = 96,\n+\tUNI_CMD_MIB_CNT_S_P20BW_2_ED_TIME = 97,\n+\tUNI_CMD_MIB_CNT_S_P20BW_3_ED_TIME = 98,\n+\tUNI_CMD_MIB_CNT_S_P20BW_4_ED_TIME = 99,\n+\tUNI_CMD_MIB_CNT_S_P20BW_5_ED_TIME = 100,\n+\tUNI_CMD_MIB_CNT_S_P20BW_6_ED_TIME = 101,\n+\tUNI_CMD_MIB_CNT_S_P20BW_7_ED_TIME = 102,\n+\tUNI_CMD_MIB_CNT_S_P20BW_8_ED_TIME = 103,\n+\tUNI_CMD_MIB_CNT_S_P20BW_9_ED_TIME = 104,\n+\tUNI_CMD_MIB_CNT_S_P20BW_10_ED_TIME = 105,\n+\tUNI_CMD_MIB_CNT_S_P20BW_11_ED_TIME = 106,\n+\tUNI_CMD_MIB_CNT_S_P20BW_12_ED_TIME = 107,\n+\tUNI_CMD_MIB_CNT_S_P20BW_13_ED_TIME = 108,\n+\tUNI_CMD_MIB_CNT_S_P20BW_14_ED_TIME = 109,\n+\tUNI_CMD_MIB_CNT_S_P20BW_15_ED_TIME = 110,\n+\tUNI_CMD_MIB_CNT_TX_BW_320MHZ = 111,\n+\tUNI_CMD_MIB_CNT_TX_DDLMT_RNG0 = 112, /* Rng0~Rng4 112~116 */\n+\tUNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_3 = 117, /* 117~120 */\n+\tUNI_CMD_MIB_CNT_BSS0_TX = 121, /* 121~124 */\n+\tUNI_CMD_MIB_CNT_BSS0_TX_DATA = 125, /* 125~128 */\n+\tUNI_CMD_MIB_CNT_BSS0_TX_BYTE = 129, /* 129~132 */\n+\tUNI_CMD_MIB_CNT_RX_OK_BSS0 = 133, /* 133~136 */\n+\tUNI_CMD_MIB_CNT_RX_BYTE_BSS0 = 137, /* 137~140 */\n+\tUNI_CMD_MIB_CNT_RX_DATA_BSS0 = 141, /* 141~144 */\n+\tUNI_CMD_MIB_CNT_MBSS0_TX_OK = 145, /* 145~160 */\n+\tUNI_CMD_MIB_CNT_MBSS0_TX_BYTE = 161, /* 161~176 */\n+\tUNI_CMD_MIB_CNT_RX_OK_MBSS0 = 177, /* 177~192 */\n+\tUNI_CMD_MIB_CNT_RX_BYTE_MBSS0 = 193, /* 193~208 */\n+\tUNI_CMD_MIB_CNT_AMPDU = 209,\n+\tUNI_CMD_MIB_CNT_AMPDU_MPDU = 210,\n+\tUNI_CMD_MIB_CNT_AMPDU_ACKED = 211,\n+\tUNI_CMD_MIB_CNT_MAX_NUM\n+};\n+\n+enum ENUM_UNI_CMD_GET_STATISTICS_TAG {\n+\tUNI_CMD_GET_STATISTICS_TAG_BASIC = 0,\n+\tUNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1,\n+\tUNI_CMD_GET_STATISTICS_TAG_STA = 2,\n+\tUNI_CMD_GET_STATISTICS_TAG_BUG_REPORT = 3,\n+\tUNI_CMD_GET_STATISTICS_TAG_EML_STATS = 6,\n+\tUNI_CMD_GET_STATISTICS_TAG_REGULAR_STATS = 7,\n+\tUNI_CMD_GET_STATISTICS_TAG_BSS_LINK_QUALITY = 8,\n+\tUNI_CMD_GET_STATISTICS_TAG_GET_ML_CHNL_COND = 9,\n+\tUNI_CMD_GET_STATISTICS_TAG_STAT_WTBL = 10,\n+\tUNI_CMD_GET_STATISTICS_TAG_LINK_LAYER_STATS = 0x80,\n+\tUNI_CMD_GET_STATISTICS_TAG_PPDU_LATENCY,\n+\tUNI_CMD_GET_STATISTICS_TAG_CURRENT_TX_RATE,\n+\tUNI_CMD_GET_STATISTICS_TAG_BEACON_REPORT = 0x86,\n+\tUNI_CMD_GET_STATISTICS_TAG_BSS_CURRENT_TX_RATE = 0x87,\n+\tUNI_CMD_GET_STATISTICS_TAG_BSS_PRED_TX_BITRATE = 0x88,\n+};\n+\n #define UNI_WOW_DETECT_TYPE_MAGIC\t\tBIT(0)\n #define UNI_WOW_DETECT_TYPE_ANY\t\t\tBIT(1)\n #define UNI_WOW_DETECT_TYPE_DISCONNECT\t\tBIT(2)\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile\nindex f9dcc0bba393c..3863a89b89742 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile\n@@ -4,7 +4,7 @@ obj-$(CONFIG_MT7925_COMMON) += mt7925-common.o\n obj-$(CONFIG_MT7925E) += mt7925e.o\n obj-$(CONFIG_MT7925U) += mt7925u.o\n \n-mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o\n+mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o stats.o\n mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o\n mt7925e-y := pci.o pci_mac.o pci_mcu.o\n mt7925u-y := usb.o\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c\nindex d01ff49de47af..ace501049792e 100644\n--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c\n@@ -1,8 +1,11 @@\n // SPDX-License-Identifier: BSD-3-Clause-Clear\n /* Copyright (C) 2023 MediaTek Inc. */\n \n+#include \u003clinux/math64.h\u003e\n+\n #include \"mt7925.h\"\n #include \"mcu.h\"\n+#include \"stats.h\"\n \n static int\n mt7925_reg_set(void *data, u64 val)\n@@ -286,6 +289,366 @@ static int mt7925_chip_reset(void *data, u64 val)\n \n DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, \"%lld\\n\");\n \n+static const u32 stats_query_mib_counters[] = {\n+\tUNI_CMD_MIB_CNT_RX_FCS_ERR,\n+\tUNI_CMD_MIB_CNT_RX_FIFO_OVERFLOW,\n+\tUNI_CMD_MIB_CNT_RX_MPDU,\n+\tUNI_CMD_MIB_CNT_AMPDU_RX_COUNT,\n+\tUNI_CMD_MIB_CNT_PF_DROP,\n+\tUNI_CMD_MIB_CNT_LEN_MISMATCH,\n+\tUNI_CMD_MIB_CNT_CHANNEL_IDLE,\n+\tUNI_CMD_MIB_CNT_CCA_NAV_TX_TIME,\n+\tUNI_CMD_MIB_CNT_MDRDY,\n+\tUNI_CMD_MIB_CNT_RX_CCK_MDRDY_TIME,\n+\tUNI_CMD_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME,\n+\tUNI_CMD_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME,\n+\tUNI_CMD_MIB_CNT_P_CCA_TIME,\n+\tUNI_CMD_MIB_CNT_S_CCA_TIME,\n+\tUNI_CMD_MIB_CNT_P_ED_TIME,\n+\tUNI_CMD_MIB_CNT_BCN_TX,\n+\tUNI_CMD_MIB_CNT_TX_BW_40MHZ,\n+\tUNI_CMD_MIB_CNT_TX_BW_80MHZ,\n+\tUNI_CMD_MIB_CNT_TX_BW_160MHZ,\n+\tUNI_CMD_MIB_CNT_BSS0_BA_MISS,\n+\tUNI_CMD_MIB_CNT_BSS0_RTS_TX_CNT,\n+\tUNI_CMD_MIB_CNT_BSS0_FRAME_RETRY,\n+\tUNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_2,\n+\tUNI_CMD_MIB_CNT_BSS0_RTS_RETRY,\n+\tUNI_CMD_MIB_CNT_BSS0_ACK_FAIL,\n+\tUNI_CMD_MIB_CNT_AMPDU,\n+\tUNI_CMD_MIB_CNT_AMPDU_MPDU,\n+\tUNI_CMD_MIB_CNT_AMPDU_ACKED,\n+};\n+\n+/* Dump the whole firmware auto-rate table and mark the entry currently in use\n+ * with \"--\u003e\"\n+ */\n+static void\n+mt7925_dump_auto_rate_table(struct seq_file *s,\n+\t\t\t const struct mt7925_wtbl_rate *wr)\n+{\n+\tu8 fcap = wr-\u003efcap;\n+\tu8 rate_idx = wr-\u003erate_idx;\n+\tu8 cbrn = wr-\u003ecbrn;\n+\tint i;\n+\n+\tseq_printf(s, \"%-22s Cur Rate Index = %u\\n\", \" \", rate_idx);\n+\n+\tfor (i = 0; i \u003c MT7925_AUTO_RATE_NUM; i++) {\n+\t\tu16 rate_code = le16_to_cpu(wr-\u003erate_code[i]);\n+\t\tu8 txmode = MT7925_HW_RATE_TO_MODE(rate_code);\n+\t\tu8 rate = MT7925_HW_RATE_TO_MCS(rate_code);\n+\t\tu8 nsts = MT7925_HW_RATE_TO_NSS(rate_code) + 1;\n+\t\tu8 stbc = MT7925_HW_RATE_TO_STBC(rate_code);\n+\t\tu8 dcm = MT7925_HW_RATE_TO_DCM(rate_code);\n+\t\tu8 ersu106t = MT7925_HW_RATE_TO_106T(rate_code);\n+\t\tu8 sgi = mt7925_wtbl_get_sgi(wr, txmode, fcap);\n+\t\tu8 ldpc = mt7925_wtbl_get_ldpc(wr, txmode);\n+\t\tconst char *mode_str = \"N/A\";\n+\n+\t\tif (dcm)\n+\t\t\trate = MT7925_HW_RATE_UNMASK_DCM(rate);\n+\t\tif (ersu106t)\n+\t\t\trate = MT7925_HW_RATE_UNMASK_106T(rate);\n+\n+\t\tif (txmode \u003c ARRAY_SIZE(mt7925_tx_mode_str))\n+\t\t\tmode_str = mt7925_tx_mode_str[txmode];\n+\n+\t\tseq_printf(s, \"Rate index[%d] %s\", i,\n+\t\t\t rate_idx == i ? \"--\u003e \" : \" \");\n+\n+\t\t/* rate/MCS field */\n+\t\tif (txmode == MT7925_TX_RATE_MODE_CCK)\n+\t\t\tseq_printf(s, \"%s, \",\n+\t\t\t\t mt7925_tx_rate_cck_str[rate \u0026 0x3]);\n+\t\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\n+\t\t\tseq_printf(s, \"%s, \", mt7925_hw_rate_ofdm_str(rate));\n+\t\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\n+\t\t\t txmode == MT7925_TX_RATE_MODE_HTGF)\n+\t\t\tseq_printf(s, \"MCS%d, \", rate);\n+\t\telse\n+\t\t\tseq_printf(s, \"%s%d_MCS%d, \",\n+\t\t\t\t stbc ? \"NSTS\" : \"NSS\", nsts, rate);\n+\n+\t\t/* bandwidth: mirror the CCK/OFDM -\u003e BW20 and cbrn handling */\n+\t\tif (txmode == MT7925_TX_RATE_MODE_CCK ||\n+\t\t txmode == MT7925_TX_RATE_MODE_OFDM)\n+\t\t\tseq_printf(s, \"%s, \", mt7925_tx_rate_bw_str[0]);\n+\t\telse if (i \u003e cbrn)\n+\t\t\tseq_printf(s, \"%s, \",\n+\t\t\t\t fcap \u003c 5 ?\n+\t\t\t\t (fcap \u003e MT7925_BW_20 ?\n+\t\t\t\t mt7925_tx_rate_bw_str[fcap - 1] :\n+\t\t\t\t mt7925_tx_rate_bw_str[fcap]) :\n+\t\t\t\t mt7925_tx_rate_bw_str[5]);\n+\t\telse\n+\t\t\tseq_printf(s, \"%s, \",\n+\t\t\t\t fcap \u003c 5 ? mt7925_tx_rate_bw_str[fcap] :\n+\t\t\t\t mt7925_tx_rate_bw_str[5]);\n+\n+\t\t/* GI / preamble */\n+\t\tif (txmode == MT7925_TX_RATE_MODE_CCK)\n+\t\t\tseq_printf(s, \"%s, \", rate \u003c 4 ? \"LP\" : \"SP\");\n+\t\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\n+\t\t\t; /* OFDM has no GI/preamble to print */\n+\t\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\n+\t\t\t txmode == MT7925_TX_RATE_MODE_HTGF ||\n+\t\t\t txmode == MT7925_TX_RATE_MODE_VHT ||\n+\t\t\t txmode == MT7925_TX_RATE_MODE_PLR)\n+\t\t\tseq_printf(s, \"%s, \", sgi == 0 ? \"LGI\" : \"SGI\");\n+\t\telse\n+\t\t\tseq_printf(s, \"%s, \",\n+\t\t\t\t sgi == 0 ? \"SGI\" :\n+\t\t\t\t (sgi == 1 ? \"MGI\" : \"LGI\"));\n+\n+\t\t/* mode, DCM, 106t, STBC, coding */\n+\t\tseq_printf(s, \"%s%s%s%s%s\\n\",\n+\t\t\t mode_str,\n+\t\t\t dcm ? \", DCM\" : \"\", ersu106t ? \", 106t\" : \"\",\n+\t\t\t stbc ? \", STBC, \" : \", \",\n+\t\t\t (ldpc == 0 ||\n+\t\t\t txmode == MT7925_TX_RATE_MODE_CCK ||\n+\t\t\t txmode == MT7925_TX_RATE_MODE_OFDM) ?\n+\t\t\t \"BCC\" : \"LDPC\");\n+\t}\n+}\n+\n+static int mt792x_stats(struct seq_file *s, void *data)\n+{\n+\ts8 rssi = 0;\n+\tu8 band_idx = 0;\n+\tbool wtbl_rate_valid = false;\n+\tint ret = 0;\n+\tint i = 0;\n+\tu32 stats_value = 0;\n+\tu32 tx_link_speed_kbps = 0;\n+\tu32 tx_per_rem = 0;\n+\t__le32 tx_ampdu_cnt = 0;\n+\tu64 tx_total = 0;\n+\tu64 tx_fail = 0;\n+\tu64 tx_per = 0;\n+\t/* UNI_CMD_MIB_DATA */\n+\tu64 mib_values[ARRAY_SIZE(stats_query_mib_counters)];\n+\tstruct mt792x_dev *dev = dev_get_drvdata(s-\u003eprivate);\n+\tstruct mt7925_wtbl_rate wtbl_rate;\n+\tstruct mt7925_sta_stats *stats = NULL;\n+\n+\tband_idx = dev-\u003emphy.band_idx;\n+\n+\tif (band_idx \u003e= MT7925_STA_STATS_BAND_NUM)\n+\t\treturn -EINVAL;\n+\n+\tstats = kzalloc(sizeof(*stats), GFP_KERNEL);\n+\tif (!stats)\n+\t\treturn -ENOMEM;\n+\n+\t/* Get STA_STATS */\n+\tmt792x_mutex_acquire(dev);\n+\tret = mt792x_mcu_get_stat(dev, stats);\n+\tmt792x_mutex_release(dev);\n+\tif (ret)\n+\t\tgoto out;\n+\n+\t/* Get MIB_STATS */\n+\tmt792x_mutex_acquire(dev);\n+\tret = mt7925_mcu_get_mib_info(dev,\n+\t\t\t\t band_idx,\n+\t\t\t\t stats_query_mib_counters,\n+\t\t\t\t ARRAY_SIZE(stats_query_mib_counters),\n+\t\t\t\t mib_values);\n+\tmt792x_mutex_release(dev);\n+\tif (ret)\n+\t\tgoto out;\n+\n+\t/* Get Link_Speed and RSSI */\n+\tmt792x_mutex_acquire(dev);\n+\tret = mt7925_mcu_get_link_quality(dev,\n+\t\t\t\t\t stats-\u003ebss_idx,\n+\t\t\t\t\t \u0026rssi,\n+\t\t\t\t\t \u0026tx_link_speed_kbps);\n+\tmt792x_mutex_release(dev);\n+\tif (ret)\n+\t\tgoto out;\n+\n+\t/* Get the firmware auto-rate table (best effort; do not abort the\n+\t * whole stats dump if the WTBL query is not available).\n+\t */\n+\tmt792x_mutex_acquire(dev);\n+\tif (!mt792x_mcu_get_wtbl_rate(dev, stats-\u003ewtbl_idx, \u0026wtbl_rate))\n+\t\twtbl_rate_valid = true;\n+\tmt792x_mutex_release(dev);\n+\n+\t/* Print STA_STATS info */\n+\tseq_printf(s, \"(STA) connected AP MAC Address = %pM\\n\",\n+\t\t stats-\u003emac_addr);\n+\tseq_printf(s, \"%-22s BssIdx = [%u]\\n\", \" \", stats-\u003ebss_idx);\n+\tseq_printf(s, \"%-22s StaRecIdx = [%u]\\n\",\n+\t\t \" \", stats-\u003esta_idx);\n+\tseq_printf(s, \"%-22s RSSI = %d\\n\", \" \", rssi);\n+\tseq_printf(s, \"%-22s Link_Speed = %u (kbit/s)\\n\",\n+\t\t \" \", tx_link_speed_kbps);\n+\n+\tseq_printf(s, \"%-22s temperature = %u\\n\",\n+\t\t \" \", stats-\u003etemperature);\n+\n+\tstats_value = le32_to_cpu(stats-\u003etransmit_count) -\n+\t\t le32_to_cpu(stats-\u003etransmit_fail_count);\n+\tseq_printf(s, \"%-22s Tx success = %u\\n\",\n+\t\t \" \", stats_value);\n+\n+\tstats_value = le32_to_cpu(stats-\u003etx_fail_count) -\n+\t\t le32_to_cpu(stats-\u003etx_life_timeout_count);\n+\tseq_printf(s, \"%-22s Tx fail to Rcv ACK after retry = %u\\n\",\n+\t\t \" \", stats_value);\n+\n+\tseq_printf(s, \"%-22s Rx Mpdu = %u\\n\",\n+\t\t \" \", le32_to_cpu(stats-\u003emib[band_idx].rx_mpdu_cnt));\n+\n+\tseq_printf(s, \"%-22s Rx Fcs Error = %u (MPDU)\\n\",\n+\t\t \" \", le32_to_cpu(stats-\u003emib[band_idx].fcs_error));\n+\tseq_printf(s, \"%-22s Rx FIFO full = %u (MPDU)\\n\",\n+\t\t \" \", le32_to_cpu(stats-\u003emib[band_idx].rx_fifo_full));\n+\n+\tfor (i = 0; i \u003c STAT_MIB_CNT_TRX_AGG_RANGE_MAX_NUM; i++) {\n+\t\ttx_ampdu_cnt = stats-\u003emib[band_idx].tx_range_ampdu_cnt[i];\n+\t\tseq_printf(s, \"%-22s TRX_AGG_RANGE[%d] = %u (PPDU)\\n\",\n+\t\t\t \" \",\n+\t\t\t i,\n+\t\t\t le32_to_cpu(tx_ampdu_cnt));\n+\t}\n+\n+\tseq_printf(s, \"%-22s MPDUs in AMPDUs transmitted = %u (MPDU)\\n\",\n+\t\t \" \", le32_to_cpu(stats-\u003emib[band_idx].ampdu_tx_sf_cnt));\n+\tseq_printf(s, \"%-22s MPDUs in AMPDUs transmitted with ACK reply = %u (MPDU)\\n\",\n+\t\t \" \", le32_to_cpu(stats-\u003emib[band_idx].ampdu_tx_ack_sf_cnt));\n+\tseq_printf(s, \"%-22s rate1_tx_cnt = %u\\n\",\n+\t\t \" \", le32_to_cpu(stats-\u003erate1_tx_cnt));\n+\tseq_printf(s, \"%-22s rate1_fail_cnt = %u\\n\",\n+\t\t \" \", le32_to_cpu(stats-\u003erate1_fail_cnt));\n+\tseq_printf(s, \"%-22s train_up = %u\\n\",\n+\t\t \" \", le16_to_cpu(stats-\u003etrain_up));\n+\tseq_printf(s, \"%-22s train_down = %u\\n\",\n+\t\t \" \", le16_to_cpu(stats-\u003etrain_down));\n+\tseq_printf(s, \"%-22s is_force_tx_stream = %u\\n\",\n+\t\t \" \", stats-\u003eis_force_tx_stream);\n+\tseq_printf(s, \"%-22s is_force_se_off = %u\\n\",\n+\t\t \" \", stats-\u003eis_force_se_off);\n+\tseq_printf(s, \"%-22s max_ampdu_factor = %u\\n\",\n+\t\t \" \", stats-\u003emax_ampdu_factor);\n+\tseq_printf(s, \"%-22s tx_rate_up_penalty = %u\\n\",\n+\t\t \" \", stats-\u003etx_rate_up_penalty);\n+\tseq_printf(s, \"%-22s low_traffic_mode = %u\\n\",\n+\t\t \" \", stats-\u003elow_traffic_mode);\n+\tseq_printf(s, \"%-22s low_traffic_count = %u\\n\",\n+\t\t \" \", stats-\u003elow_traffic_count);\n+\tseq_printf(s, \"%-22s low_traffic_dashboard = %u\\n\",\n+\t\t \" \", stats-\u003elow_traffic_dashboard);\n+\tseq_printf(s, \"%-22s dynamic_sgi_state = %u\\n\",\n+\t\t \" \", stats-\u003edynamic_sgi_state);\n+\tseq_printf(s, \"%-22s dynamic_sgi_score = %u\\n\",\n+\t\t \" \", stats-\u003edynamic_sgi_score);\n+\tseq_printf(s, \"%-22s dynamic_bw_state = %u\\n\",\n+\t\t \" \", stats-\u003edynamic_bw_state);\n+\tseq_printf(s, \"%-22s dynamic_gband_256qam_state = %u\\n\",\n+\t\t \" \", stats-\u003edynamic_gband_256qam_state);\n+\tseq_printf(s, \"%-22s vht_non_sp_rate_state = %u\\n\",\n+\t\t \" \", stats-\u003evht_non_sp_rate_state);\n+\n+\t/* Decode the TX Vector BBP latch to show the current TX MCS rate */\n+\tmt7925_print_last_tx_rate(s, stats-\u003etx_vector[band_idx].txv);\n+\n+\t/* Dump the whole firmware auto-rate table\n+\t * and mark the entry currently in use.\n+\t */\n+\tif (wtbl_rate_valid)\n+\t\tmt7925_dump_auto_rate_table(s, \u0026wtbl_rate);\n+\n+\tseq_puts(s, \"\\nmib state:\\n\");\n+\t/* ===Rx Related Counters=== */\n+\tseq_puts(s, \"=== Rx Related Counters ===\\n\");\n+\tseq_printf(s, \"%-22s Rx with CRC = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_RX_FCS_ERR]);\n+\tseq_printf(s, \"%-22s Rx drop due to out of resource = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_RX_FIFO_OVERFLOW]);\n+\tseq_printf(s, \"%-22s Rx Mpdu = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_RX_MPDU]);\n+\tseq_printf(s, \"%-22s Rx AMpdu = %llu (PPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_AMPDU_RX_COUNT]);\n+\tseq_printf(s, \"%-22s Rx PF Drop = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_PF_DROP]);\n+\tseq_printf(s, \"%-22s Rx Len Mismatch = %llu (PPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_LEN_MISMATCH]);\n+\n+\t/* ===Phy/Timing Related Counters=== */\n+\tseq_puts(s, \"\\n=== Phy/Timing Related Counters ===\\n\");\n+\tseq_printf(s, \"%-22s ChannelIdleCnt = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_CHANNEL_IDLE]);\n+\tseq_printf(s, \"%-22s CCA_NAV_Tx_Time = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_CCA_NAV_TX_TIME]);\n+\tseq_printf(s, \"%-22s Rx_MDRDY_CNT = %llu (PPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_MDRDY]);\n+\tseq_printf(s, \"%-22s CCK_MDRDY = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_RX_CCK_MDRDY_TIME]);\n+\tseq_printf(s, \"%-22s OFDM_MDRDY = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME]);\n+\tseq_printf(s, \"%-22s OFDM_GREEN_MDRDY = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME]);\n+\tseq_printf(s, \"%-22s Prim CCA Time = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_P_CCA_TIME]);\n+\tseq_printf(s, \"%-22s Sec CCA Time = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_S_CCA_TIME]);\n+\tseq_printf(s, \"%-22s Prim ED Time = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_P_ED_TIME]);\n+\n+\t/* ===Tx Related Counters(Generic)=== */\n+\tseq_puts(s, \"\\n=== Tx Related Counters(Generic) ===\\n\");\n+\tseq_printf(s, \"%-22s BeaconTxCnt = %llu\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_BCN_TX]);\n+\tseq_printf(s, \"%-22s Tx 40MHz Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_TX_BW_40MHZ]);\n+\tseq_printf(s, \"%-22s Tx 80MHz Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_TX_BW_80MHZ]);\n+\tseq_printf(s, \"%-22s Tx 160MHz Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_TX_BW_160MHZ]);\n+\n+\t/* ===BSSID[0] Related Counters=== */\n+\tseq_puts(s, \"\\n=== BSSID[0] Related Counters ===\\n\");\n+\tseq_printf(s, \"%-22s BA Miss Cnt = %llu (PPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_BSS0_BA_MISS]);\n+\tseq_printf(s, \"%-22s RTS Tx Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_BSS0_RTS_TX_CNT]);\n+\tseq_printf(s, \"%-22s Frame Retry Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_BSS0_FRAME_RETRY]);\n+\tseq_printf(s, \"%-22s Frame Retry 2 Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_BSS0_FRAME_RETRY_2]);\n+\tseq_printf(s, \"%-22s RTS Retry Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_BSS0_RTS_RETRY]);\n+\tseq_printf(s, \"%-22s Ack Failed Cnt = %llu (PPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_BSS0_ACK_FAIL]);\n+\n+\t/* ===AMPDU Related Counters=== */\n+\tseq_puts(s, \"\\n=== AMPDU Related Counters ===\\n\");\n+\tseq_printf(s, \"%-22s Tx AMPDU_Pkt_Cnt = %llu (PPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_AMPDU]);\n+\tseq_printf(s, \"%-22s Tx AMPDU_MPDU_Pkt_Cnt = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_AMPDU_MPDU]);\n+\tseq_printf(s, \"%-22s AMPDU Tx success = %llu (MPDU)\\n\",\n+\t\t \" \", mib_values[QUERY_MIB_CNT_AMPDU_ACKED]);\n+\n+\ttx_total = mib_values[QUERY_MIB_CNT_AMPDU_MPDU];\n+\ttx_fail = mib_values[QUERY_MIB_CNT_AMPDU_MPDU] -\n+\t\t mib_values[QUERY_MIB_CNT_AMPDU_ACKED];\n+\ttx_per = tx_total == 0 ? 0 : div64_u64(1000 * tx_fail, tx_total);\n+\tseq_printf(s, \"%-22s AMPDU Tx fail count = %llu (MPDU), PER=%llu.%1llu%%\\n\",\n+\t\t \" \",\n+\t\t tx_fail,\n+\t\t div_u64_rem(tx_per, 10, \u0026tx_per_rem), (u64)tx_per_rem);\n+\n+out:\n+\tkfree(stats);\n+\treturn ret;\n+}\n+\n int mt7925_init_debugfs(struct mt792x_dev *dev)\n {\n \tstruct dentry *dir;\n@@ -313,5 +676,8 @@ int mt7925_init_debugfs(struct mt792x_dev *dev)\n \t\t\t\t mt792x_pm_stats);\n \tdebugfs_create_file(\"deep-sleep\", 0600, dir, dev, \u0026fops_ds);\n \n+\tdebugfs_create_devm_seqfile(dev-\u003emt76.dev, \"stats\", dir,\n+\t\t\t\t mt792x_stats);\n+\n \treturn 0;\n }\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/stats.c b/drivers/net/wireless/mediatek/mt76/mt7925/stats.c\nnew file mode 100644\nindex 0000000000000..874c0b979c264\n--- /dev/null\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/stats.c\n@@ -0,0 +1,587 @@\n+// SPDX-License-Identifier: BSD-3-Clause-Clear\n+/* Copyright (C) 2026 MediaTek Inc. */\n+\n+#include \u003clinux/firmware.h\u003e\n+#include \u003clinux/fs.h\u003e\n+#include \"mt7925.h\"\n+#include \"mcu.h\"\n+#include \"mac.h\"\n+#include \"stats.h\"\n+\n+#define MT7925_STA_STATS_VERSION 1\n+#define MT7925_STA_STATS_VALID 1U\n+\n+#define MT7925_MIB_MAX_CNT\t\t\t32\n+\n+/* firmware UNI_CMD_MIB_CNT_MAX_NUM upper bound */\n+#define MT7925_MIB_CNT_MAX_NUM\t\t512\n+\n+#define MT7925_LQ_BAND_NUM\t4\t\t\t/* Link quality band */\n+\n+const char * const mt7925_tx_mode_str[] = {\n+\t\"CCK\", \"OFDM\", \"MM\", \"GF\", \"VHT\", \"PLR\",\n+\t\"PLRP\", \"ALR\", \"HE_SU\", \"HE_ER\", \"HE_TRIG\", \"HE_MU\",\n+\t\"EHT_ER\", \"TOF\", \"EHT_TRIG\", \"EHT_MU\"\n+};\n+\n+const char * const mt7925_tx_rate_cck_str[] = {\n+\t\"1M\", \"2M\", \"5.5M\", \"11M\", \"N/A\"\n+};\n+\n+const char * const mt7925_tx_rate_bw_str[] = {\n+\t\"BW20\", \"BW40\", \"BW80\", \"BW160/BW8080\", \"BW320\", \"N/A\"\n+};\n+\n+struct mt7925_sta_stats_req {\n+\tu8 rsv[4];\n+\t__le16 tag;\n+\t__le16 len;\n+\tu8 sta_rec_idx;\n+\tu8 rsv1;\n+\tu8 lls_read_clear;\n+\tu8 reset_counter;\n+} __packed;\n+\n+struct mt7925_sta_stats_event {\n+\tu8 rsv[4];\n+\t__le16 tag;\n+\t__le16 len;\n+\tstruct mt7925_sta_stats stats;\n+} __packed;\n+\n+/* WTBL auto-rate request TLV, mirror Gen4m struct UNI_CMD_STAT_WTBL.\n+ * The RA tag reuses UNI_CMD_ID_STATISTICS_WTBL (10).\n+ */\n+struct mt7925_wtbl_rate_req {\n+\tu8 rsv[4];\n+\t__le16 tag;\n+\t__le16 len;\n+\t__le16 wlan_idx;\n+\t__le16 rsv1;\n+} __packed;\n+\n+/* WTBL auto-rate event TLV. Firmware answers cmd tag 10 with event tag 12. */\n+struct mt7925_wtbl_rate_event {\n+\tu8 rsv[4];\n+\tstruct mt7925_wtbl_rate rate;\n+} __packed;\n+\n+/* fixed field, mirror UNI_(CMD|EVENT)_MIB_INFO */\n+struct mt7925_mib_hdr {\n+\tu8 band_idx;\n+\tu8 rsv[3];\n+} __packed;\n+\n+/* One requested/returned MIB counter, mirror UNI_(CMD|EVENT)_MIB_DATA_T. */\n+struct mt7925_mib_data {\n+\t__le16 tag;\t/* UNI_(CMD|EVENT)_MIB_DATA = 0 */\n+\t__le16 len;\n+\t__le32 counter;\t/* MIB counter ID (enum mt7925_mib_counter) */\n+\t__le64 data;\t/* only valid on event; ignored on cmd */\n+} __packed;\n+\n+/* per-band link quality entry, mirror UNI_LINK_QUALITY */\n+struct mt7925_link_quality {\n+\ts8 rssi;\t\t/* moving-average beacon RSSI of connected AP */\n+\ts8 link_quality;\t/* always 0 */\n+\t__le16 link_speed;\t/* TX rate1, unit 500 Kb/s */\n+\tu8 medium_busy_pct;\t/* always 0 */\n+\tu8 is_ready;\t\t/* 0: fields invalid, 1: valid */\n+\tu8 rsv[2];\n+} __packed;\n+\n+/* request TLV, mirror UNI_CMD_LINK_QUALITY (header + tag/len only) */\n+struct mt7925_lq_req {\n+\tu8 rsv[4]; /* UNI_CMD_GET_STATISTICS fixed field */\n+\t__le16 tag; /* UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1 */\n+\t__le16 len;\n+} __packed;\n+\n+/* event TLV, mirror UNI_EVENT_LINK_QUALITY */\n+struct mt7925_lq_event {\n+\tu8 rsv[4];\t\t/* UNI_EVENT_STATISTICS fixed field */\n+\t__le16 tag;\t\t/* UNI_EVENT_ID_STATISTICS_LINK_QUALITY = 1 */\n+\t__le16 len;\n+\tstruct mt7925_link_quality lq[MT7925_LQ_BAND_NUM];\n+} __packed;\n+\n+static void\n+mt7925_get_ap_sta_rec_idx_iter(void *data, u8 *mac,\n+\t\t\t struct ieee80211_vif *vif)\n+{\n+\tstruct mt7925_sta_rec_lookup *lookup = data;\n+\tstruct mt792x_vif *mvif;\n+\tstruct mt792x_sta *msta;\n+\n+\tif (lookup-\u003esta_rec_idx \u003e= 0)\n+\t\treturn;\n+\n+\tif (vif-\u003etype != NL80211_IFTYPE_STATION || !vif-\u003ecfg.assoc)\n+\t\treturn;\n+\n+\tmvif = (struct mt792x_vif *)vif-\u003edrv_priv;\n+\tmsta = mvif-\u003ewep_sta;\n+\tif (!msta)\n+\t\treturn;\n+\n+\tif (!msta-\u003edeflink.wcid.sta)\n+\t\treturn;\n+\n+\tlookup-\u003esta_rec_idx = msta-\u003edeflink.wcid.idx;\n+}\n+\n+int\n+mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx)\n+{\n+\tstruct mt7925_sta_rec_lookup lookup = {\n+\t\t.sta_rec_idx = -1,\n+\t};\n+\n+\tlockdep_assert_held(\u0026dev-\u003emt76.mutex);\n+\n+\tieee80211_iterate_active_interfaces(dev-\u003emphy.hw,\n+\t\t\t\t\t IEEE80211_IFACE_ITER_RESUME_ALL,\n+\t\t\t\t\t mt7925_get_ap_sta_rec_idx_iter,\n+\t\t\t\t\t \u0026lookup);\n+\n+\tif (lookup.sta_rec_idx \u003c 0)\n+\t\treturn -ENOTCONN;\n+\n+\tif (lookup.sta_rec_idx \u003e U8_MAX)\n+\t\treturn -ERANGE;\n+\n+\t*sta_rec_idx = lookup.sta_rec_idx;\n+\n+\treturn 0;\n+}\n+\n+/* Decode the TX Vector BBP latch and print the last TX rate */\n+void\n+mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3])\n+{\n+\tconst char *mode_str = \"N/A\";\n+\tu8 rate, txmode, frmode, sgi, ldpc, nsts, stbc, spe, dcm, ersu106t;\n+\ts8 txpwr, pos_txpwr;\n+\tu32 txv[3];\n+\n+\ttxv[0] = le32_to_cpu(le_txv[0]);\n+\ttxv[1] = le32_to_cpu(le_txv[1]);\n+\ttxv[2] = le32_to_cpu(le_txv[2]);\n+\n+\tif (txv[0] == 0xffffffff) {\n+\t\tseq_printf(s, \"%-22s %s = %s\\n\", \" \", \"Last TX Rate\", \"N/A\");\n+\t\tseq_printf(s, \"%-22s %s = %s\\n\",\n+\t\t\t \" \", \"Chip Out TX Power\", \"N/A\");\n+\t\treturn;\n+\t}\n+\n+\trate = MT7925_TXV_GET_TX_RATE(txv);\n+\ttxmode = MT7925_TXV_GET_TX_MODE(txv);\n+\tfrmode = MT7925_TXV_GET_TX_FRMODE(txv);\n+\tnsts = MT7925_TXV_GET_TX_NSTS(txv) + 1;\n+\tsgi = MT7925_TXV_GET_TX_SGI(txv);\n+\tldpc = MT7925_TXV_GET_TX_LDPC(txv);\n+\tstbc = MT7925_TXV_GET_TX_STBC(txv);\n+\ttxpwr = MT7925_TXV_GET_TX_PWR(txv);\n+\tspe = MT7925_TXV_GET_TX_SPE_IDX(txv);\n+\tdcm = MT7925_TXV_GET_TX_DCM(txv);\n+\tersu106t = MT7925_TXV_GET_TX_106T(txv);\n+\n+\tif (dcm)\n+\t\trate = MT7925_TXV_RATE_UNMASK_DCM(rate);\n+\tif (ersu106t)\n+\t\trate = MT7925_TXV_RATE_UNMASK_106T(rate);\n+\n+\tif (txmode \u003c ARRAY_SIZE(mt7925_tx_mode_str))\n+\t\tmode_str = mt7925_tx_mode_str[txmode];\n+\n+\tseq_printf(s, \"%-22s %s = \", \" \", \"Last TX Rate\");\n+\n+\t/* rate/MCS field */\n+\tif (txmode == MT7925_TX_RATE_MODE_CCK)\n+\t\tseq_printf(s, \"%s, \",\n+\t\t\t rate \u003c 4 ? mt7925_tx_rate_cck_str[rate] :\n+\t\t\t (((rate \u003e= 5) \u0026\u0026 (rate \u003c= 7)) ?\n+\t\t\t mt7925_tx_rate_cck_str[rate - 4] :\n+\t\t\t mt7925_tx_rate_cck_str[4]));\n+\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\n+\t\tseq_printf(s, \"%s, \", mt7925_hw_rate_ofdm_str(rate));\n+\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\n+\t\t txmode == MT7925_TX_RATE_MODE_HTGF)\n+\t\tseq_printf(s, \"MCS%d, \", rate);\n+\telse\n+\t\tseq_printf(s, \"%s%d_MCS%d, \",\n+\t\t\t stbc ? \"NSTS\" : \"NSS\", nsts, rate);\n+\n+\t/* bandwidth */\n+\tseq_printf(s, \"%s, \",\n+\t\t frmode \u003c 5 ? mt7925_tx_rate_bw_str[frmode] :\n+\t\t mt7925_tx_rate_bw_str[5]);\n+\n+\t/* GI / preamble */\n+\tif (txmode == MT7925_TX_RATE_MODE_CCK)\n+\t\tseq_printf(s, \"%s, \", rate \u003c 4 ? \"LP\" : \"SP\");\n+\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\n+\t\t; /* OFDM has no GI/preamble to print */\n+\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\n+\t\t txmode == MT7925_TX_RATE_MODE_HTGF ||\n+\t\t txmode == MT7925_TX_RATE_MODE_VHT ||\n+\t\t txmode == MT7925_TX_RATE_MODE_PLR)\n+\t\tseq_printf(s, \"%s, \", sgi == 0 ? \"LGI\" : \"SGI\");\n+\telse\n+\t\tseq_printf(s, \"%s, \",\n+\t\t\t sgi == 0 ? \"SGI\" : (sgi == 1 ? \"MGI\" : \"LGI\"));\n+\n+\t/* mode, DCM, 106t, STBC, coding, SPE */\n+\tseq_printf(s, \"%s%s%s%s%s%s%d\\n\",\n+\t\t mode_str,\n+\t\t dcm ? \", DCM\" : \"\", ersu106t ? \", 106t\" : \"\",\n+\t\t stbc ? \", STBC, \" : \", \", ldpc == 0 ? \"BCC\" : \"LDPC\",\n+\t\t \", SPE\", spe);\n+\n+\t/* chip out TX power (unit: 0.5 dBm) */\n+\tpos_txpwr = (txpwr \u003c 0) ? (~txpwr + 1) : txpwr;\n+\tseq_printf(s, \"%-22s %s = %c%d.%1d dBm\\n\",\n+\t\t \" \", \"Chip Out TX Power\",\n+\t\t (txpwr \u003c 0) ? '-' : '+',\n+\t\t (pos_txpwr / 2), 5 * (pos_txpwr % 2));\n+}\n+\n+/* Guard interval used for the auto-rate entries, mirror Gen4m\n+ * connac3x_get_sgi_info_from_fw(): pick the per-mode/per-BW flag.\n+ */\n+u8\n+mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap)\n+{\n+\tbool he = (txmode == MT7925_TX_RATE_MODE_HE_SU ||\n+\t\t txmode == MT7925_TX_RATE_MODE_HE_ER ||\n+\t\t txmode == MT7925_TX_RATE_MODE_HE_TRIG ||\n+\t\t txmode == MT7925_TX_RATE_MODE_HE_MU);\n+\tbool eht = (txmode == MT7925_TX_RATE_MODE_EHT_ER ||\n+\t\t txmode == MT7925_TX_RATE_MODE_EHT_TRIG ||\n+\t\t txmode == MT7925_TX_RATE_MODE_EHT_MU);\n+\n+\tif (eht)\n+\t\treturn wr-\u003egi_eht;\n+\n+\tswitch (fcap) {\n+\tcase MT7925_BW_20:\n+\t\treturn he ? wr-\u003eg2_he : wr-\u003eg2;\n+\tcase MT7925_BW_40:\n+\t\treturn he ? wr-\u003eg4_he : wr-\u003eg4;\n+\tcase MT7925_BW_80:\n+\t\treturn he ? wr-\u003eg8_he : wr-\u003eg8;\n+\tcase MT7925_BW_160:\n+\t\treturn he ? wr-\u003eg16_he : wr-\u003eg16;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n+/* Coding used for the auto-rate entries, mirror Gen4m\n+ * connac3x_wtbl_get_ldpc_info_from_fw(): 0 = BCC, 1 = LDPC.\n+ */\n+u8\n+mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode)\n+{\n+\tswitch (txmode) {\n+\tcase MT7925_TX_RATE_MODE_HTMIX:\n+\tcase MT7925_TX_RATE_MODE_HTGF:\n+\t\treturn wr-\u003eht_ldpc;\n+\tcase MT7925_TX_RATE_MODE_VHT:\n+\t\treturn wr-\u003evht_ldpc;\n+\tcase MT7925_TX_RATE_MODE_HE_SU:\n+\tcase MT7925_TX_RATE_MODE_HE_ER:\n+\tcase MT7925_TX_RATE_MODE_HE_TRIG:\n+\tcase MT7925_TX_RATE_MODE_HE_MU:\n+\t\treturn wr-\u003ehe_ldpc;\n+\tcase MT7925_TX_RATE_MODE_EHT_ER:\n+\tcase MT7925_TX_RATE_MODE_EHT_TRIG:\n+\tcase MT7925_TX_RATE_MODE_EHT_MU:\n+\t\treturn wr-\u003eeht_ldpc;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n+int mt792x_mcu_get_stat(struct mt792x_dev *dev,\n+\t\t\tstruct mt7925_sta_stats *stats)\n+{\n+\tu16 len = 0;\n+\tint ret = 0;\n+\tstruct mt7925_sta_stats_event *event = NULL;\n+\tstruct sk_buff *skb = NULL;\n+\tstruct mt7925_sta_stats_req req = {\n+\t\t.tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_STA),\n+\t\t.len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),\n+\t\t.lls_read_clear = false,\n+\t\t.reset_counter = false,\n+\t};\n+\n+\tret = mt7925_get_ap_sta_rec_idx(dev, \u0026req.sta_rec_idx);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (!stats)\n+\t\treturn -EINVAL;\n+\n+\tret = mt76_mcu_send_and_get_msg(\u0026dev-\u003emt76,\n+\t\t\t\t\tMCU_UNI_QUERY(GET_STAT_INFO),\n+\t\t\t\t\t\u0026req, sizeof(req), true, \u0026skb);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tevent = (struct mt7925_sta_stats_event *)skb-\u003edata;\n+\n+\tif (le16_to_cpu(event-\u003etag) != UNI_CMD_ID_STATISTICS_STA) {\n+\t\tret = -EPROTO;\n+\t\tgoto out;\n+\t}\n+\n+\tlen = le16_to_cpu(event-\u003elen);\n+\tif (len \u003c sizeof(*event) - sizeof(event-\u003ersv) ||\n+\t len \u003e skb-\u003elen - sizeof(event-\u003ersv) || !IS_ALIGNED(len, 4)) {\n+\t\tret = -EMSGSIZE;\n+\t\tgoto out;\n+\t}\n+\n+\tif (event-\u003estats.version != MT7925_STA_STATS_VERSION) {\n+\t\tret = -EPROTO;\n+\t\tgoto out;\n+\t}\n+\n+\tif (!(le32_to_cpu(event-\u003estats.flags) \u0026 MT7925_STA_STATS_VALID)) {\n+\t\tret = -ENOENT;\n+\t\tgoto out;\n+\t}\n+\n+\tmemcpy(stats, \u0026event-\u003estats, sizeof(*stats));\n+\n+out:\n+\tdev_kfree_skb(skb);\n+\treturn ret;\n+}\n+\n+int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,\n+\t\t\t const u32 *counters, u8 counter_num,\n+\t\t\t u64 *values)\n+{\n+\tu8 *req;\n+\tu8 *tlv, *tlv_end;\n+\tu16 req_len;\n+\tint i, ret;\n+\tstruct mt7925_mib_hdr *req_hdr;\n+\tstruct mt7925_mib_data *req_tlv;\n+\tstruct sk_buff *skb;\n+\n+\tif (!counters || !values || !counter_num ||\n+\t counter_num \u003e MT7925_MIB_MAX_CNT)\n+\t\treturn -EINVAL;\n+\n+\t/* clear output; counters not returned by firmware stay 0 */\n+\tmemset(values, 0, counter_num * sizeof(*values));\n+\n+\treq_len = sizeof(struct mt7925_mib_hdr) +\n+\t\t counter_num * sizeof(struct mt7925_mib_data);\n+\n+\treq = kzalloc(req_len, GFP_KERNEL);\n+\tif (!req)\n+\t\treturn -ENOMEM;\n+\n+\treq_hdr = (struct mt7925_mib_hdr *)req;\n+\treq_hdr-\u003eband_idx = band_idx;\n+\n+\treq_tlv = (struct mt7925_mib_data *)(req + sizeof(*req_hdr));\n+\tfor (i = 0; i \u003c counter_num; i++) {\n+\t\treq_tlv[i].tag = cpu_to_le16(UNI_CMD_MIB_DATA);\n+\t\treq_tlv[i].len = cpu_to_le16(sizeof(struct mt7925_mib_data));\n+\t\treq_tlv[i].counter = cpu_to_le32(counters[i]);\n+\t}\n+\n+\tret = mt76_mcu_send_and_get_msg(\u0026dev-\u003emt76,\n+\t\t\t\t\tMCU_UNI_QUERY(GET_MIB_INFO), req,\n+\t\t\t\t\treq_len, true, \u0026skb);\n+\tkfree(req);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (skb-\u003elen \u003c sizeof(struct mt7925_mib_hdr)) {\n+\t\tret = -EMSGSIZE;\n+\t\tgoto out;\n+\t}\n+\n+\t/* walk the returned TLVs, match each counter ID to the request */\n+\ttlv = skb-\u003edata + sizeof(struct mt7925_mib_hdr);\n+\ttlv_end = skb-\u003edata + skb-\u003elen;\n+\n+\twhile (tlv + sizeof(struct mt7925_mib_data) \u003c= tlv_end) {\n+\t\tstruct mt7925_mib_data *evt_tlv =\n+\t\t\t(struct mt7925_mib_data *)tlv;\n+\t\tu16 tag = le16_to_cpu(evt_tlv-\u003etag);\n+\t\tu16 len = le16_to_cpu(evt_tlv-\u003elen);\n+\t\tu32 counter;\n+\n+\t\tif (len \u003c sizeof(struct mt7925_mib_data) ||\n+\t\t tlv + len \u003e tlv_end)\n+\t\t\tbreak;\n+\n+\t\tif (tag == UNI_CMD_MIB_DATA) {\n+\t\t\tcounter = le32_to_cpu(evt_tlv-\u003ecounter);\n+\n+\t\t\tif (counter \u003c MT7925_MIB_CNT_MAX_NUM) {\n+\t\t\t\tfor (i = 0; i \u003c counter_num; i++) {\n+\t\t\t\t\tif (counters[i] == counter) {\n+\t\t\t\t\t\tvalues[i] =\n+\t\t\t\t\t\t le64_to_cpu(evt_tlv-\u003edata);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t\ttlv += len;\n+\t}\n+\n+\tret = 0;\n+\n+out:\n+\tdev_kfree_skb(skb);\n+\n+\treturn ret;\n+}\n+\n+char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx)\n+{\n+\tchar * const ofdm_str[] = {\n+\t\t\"6M\", \"9M\", \"12M\", \"18M\", \"24M\", \"36M\", \"48M\", \"54M\", \"N/A\"\n+\t};\n+\n+\tswitch (ofdm_idx) {\n+\tcase 11: return ofdm_str[0];\t/* 6M */\n+\tcase 15: return ofdm_str[1];\t/* 9M */\n+\tcase 10: return ofdm_str[2];\t/* 12M */\n+\tcase 14: return ofdm_str[3];\t/* 18M */\n+\tcase 9: return ofdm_str[4];\t/* 24M */\n+\tcase 13: return ofdm_str[5];\t/* 36M */\n+\tcase 8: return ofdm_str[6];\t/* 48M */\n+\tcase 12: return ofdm_str[7];\t/* 54M */\n+\tdefault: return ofdm_str[8];\n+\t}\n+}\n+\n+/* mt792x_mcu_get_wtbl_rate - fetch the firmware auto-rate table for a WCID\n+ * @dev:\tdevice\n+ * @wlan_idx:\tHW WTBL / WCID index (see mt7925_sta_stats.wtbl_idx)\n+ * @rate:\tout, filled with the auto-rate table snapshot\n+ *\n+ * Mirror of Gen4m wlanoidGetStatWtbl(): send UNI_CMD_GET_STAT_INFO with the\n+ * WTBL rate TLV (cmd tag 10) and parse the reply (event tag 12) into @rate.\n+ *\n+ * Return: 0 on success, negative errno otherwise.\n+ */\n+int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,\n+\t\t\t struct mt7925_wtbl_rate *rate)\n+{\n+\tint ret;\n+\tstruct mt7925_wtbl_rate_event *event = NULL;\n+\tstruct sk_buff *skb = NULL;\n+\tstruct mt7925_wtbl_rate_req req = {\n+\t\t.tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_WTBL),\n+\t\t.len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),\n+\t\t.wlan_idx = cpu_to_le16(wlan_idx),\n+\t};\n+\n+\tif (!rate)\n+\t\treturn -EINVAL;\n+\n+\tret = mt76_mcu_send_and_get_msg(\u0026dev-\u003emt76,\n+\t\t\t\t\tMCU_UNI_QUERY(GET_STAT_INFO),\n+\t\t\t\t\t\u0026req, sizeof(req), true, \u0026skb);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (skb-\u003elen \u003c sizeof(*event)) {\n+\t\tret = -EMSGSIZE;\n+\t\tgoto out;\n+\t}\n+\n+\tevent = (struct mt7925_wtbl_rate_event *)skb-\u003edata;\n+\n+\tif (le16_to_cpu(event-\u003erate.tag) != MT7925_UNI_EVENT_STATISTICS_WTBL) {\n+\t\tret = -EPROTO;\n+\t\tgoto out;\n+\t}\n+\n+\tmemcpy(rate, \u0026event-\u003erate, sizeof(*rate));\n+\tret = 0;\n+\n+out:\n+\tdev_kfree_skb(skb);\n+\treturn ret;\n+}\n+\n+/**\n+ * mt7925_mcu_get_link_quality - query RSSI and TX link speed for a band\n+ * @dev:\tdevice\n+ * @band_idx:\tband/BSS index (0..3)\n+ * @rssi:\tout, moving-average beacon RSSI in dBm (may be NULL)\n+ * @tx_link_speed_kbps: out, TX rate in kbit/s (may be NULL)\n+ *\n+ * Return: 0 on success, -ENOENT if the band's link quality is not ready.\n+ *\n+ * Only RSSI and TX rate come from firmware here; for RX rate read wcid-\u003erate.\n+ */\n+int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,\n+\t\t\t\ts8 *rssi, u32 *tx_link_speed_kbps)\n+{\n+\tint ret;\n+\tstruct mt7925_lq_event *event;\n+\tstruct mt7925_link_quality *lq;\n+\tstruct sk_buff *skb;\n+\tstruct mt7925_lq_req req = {\n+\t\t.tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_LINK_QUALITY),\n+\t\t.len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),\n+\t};\n+\n+\tif (band_idx \u003e= MT7925_LQ_BAND_NUM)\n+\t\treturn -EINVAL;\n+\n+\tret = mt76_mcu_send_and_get_msg(\u0026dev-\u003emt76,\n+\t\t\t\t\tMCU_UNI_QUERY(GET_STAT_INFO), \u0026req,\n+\t\t\t\t\tsizeof(req), true, \u0026skb);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (skb-\u003elen \u003c sizeof(*event)) {\n+\t\tret = -EMSGSIZE;\n+\t\tgoto out;\n+\t}\n+\n+\tevent = (struct mt7925_lq_event *)skb-\u003edata;\n+\n+\tif (le16_to_cpu(event-\u003etag) != UNI_CMD_ID_STATISTICS_LINK_QUALITY) {\n+\t\tret = -EPROTO;\n+\t\tgoto out;\n+\t}\n+\n+\tlq = \u0026event-\u003elq[band_idx];\n+\tif (!lq-\u003eis_ready) {\n+\t\tret = -ENOENT;\n+\t\tgoto out;\n+\t}\n+\n+\tif (rssi)\n+\t\t*rssi = lq-\u003erssi;\n+\n+\t/* firmware reports TX rate in 500 Kb/s units -\u003e kbit/s */\n+\tif (tx_link_speed_kbps)\n+\t\t*tx_link_speed_kbps = le16_to_cpu(lq-\u003elink_speed) * 500;\n+\n+\tret = 0;\n+\n+out:\n+\tdev_kfree_skb(skb);\n+\n+\treturn ret;\n+}\ndiff --git a/drivers/net/wireless/mediatek/mt76/mt7925/stats.h b/drivers/net/wireless/mediatek/mt76/mt7925/stats.h\nnew file mode 100644\nindex 0000000000000..a70b9eb3aa806\n--- /dev/null\n+++ b/drivers/net/wireless/mediatek/mt76/mt7925/stats.h\n@@ -0,0 +1,309 @@\n+/* SPDX-License-Identifier: BSD-3-Clause-Clear */\n+/* Copyright (C) 2026 MediaTek Inc. */\n+\n+#ifndef __MT7925_STATS_H\n+#define __MT7925_STATS_H\n+\n+#include \u003clinux/if_ether.h\u003e\n+#include \u003clinux/types.h\u003e\n+#include \"../mt76_connac_mcu.h\"\n+\n+#define MT7925_STA_STATS_AC_NUM 4\n+#define MT7925_STA_STATS_BAND_NUM 2\n+#define MT7925_STA_STATS_AGG_RANGE_NUM 16\n+#define MT7925_STA_STATS_TX_QUALITY_NUM 4\n+#define MT7925_TX_MODE_NUM 16\n+#define MT7925_TX_RATE_CCK_NUM 5\n+#define MT7925_TX_RATE_BW_NUM 6\n+\n+/* HW rate code (16-bit) field extract, mirror Gen4m CONNAC3X_HW_TX_RATE_TO_*.\n+ * The auto-rate table stores one rate code per entry.\n+ */\n+#define MT7925_HW_RATE_TO_MCS(_x)\t(((_x) \u0026 GENMASK(5, 0)) \u003e\u003e 0)\n+#define MT7925_HW_RATE_TO_MODE(_x)\t(((_x) \u0026 GENMASK(9, 6)) \u003e\u003e 6)\n+#define MT7925_HW_RATE_TO_NSS(_x)\t(((_x) \u0026 GENMASK(13, 10)) \u003e\u003e 10)\n+#define MT7925_HW_RATE_TO_STBC(_x)\t(((_x) \u0026 BIT(14)) \u003e\u003e 14)\n+#define MT7925_HW_RATE_TO_DCM(_x)\t(((_x) \u0026 BIT(4)) \u003e\u003e 4)\n+#define MT7925_HW_RATE_TO_106T(_x)\t(((_x) \u0026 BIT(5)) \u003e\u003e 5)\n+#define MT7925_HW_RATE_UNMASK_DCM(_r)\t((u8)(_r) \u0026 0xef)\n+#define MT7925_HW_RATE_UNMASK_106T(_r)\t((u8)(_r) \u0026 0xdf)\n+\n+/* Number of entries in the firmware auto-rate table (mirror Gen4m\n+ * AUTO_RATE_NUM). RA cycles through these and reports which one is in use\n+ * via wtbl-\u003erate_idx.\n+ */\n+#define MT7925_AUTO_RATE_NUM 8\n+\n+/* Firmware EVENT_STATISTICS sub-event tags. The WTBL rate request uses cmd tag\n+ * UNI_CMD_ID_STATISTICS_WTBL (10) but the firmware replies with event tag 12.\n+ */\n+#define MT7925_UNI_EVENT_STATISTICS_WTBL 12\n+\n+/* CONNAC3X TX Vector BBP latch bit fields (mirror cmm_asic_connac3x.h).\n+ * These operate on the 3-DWORD tx_vector[band].txv[3] array.\n+ */\n+#define MT7925_TXV_GET_TX_RATE(_txv)\t((_txv)[2] \u0026 0x7f)\n+#define MT7925_TXV_GET_TX_LDPC(_txv)\t(((_txv)[2] \u0026 (0x1 \u003c\u003c 7)) \u003e\u003e 7)\n+#define MT7925_TXV_GET_TX_STBC(_txv)\t(((_txv)[0] \u0026 (0x3 \u003c\u003c 6)) \u003e\u003e 6)\n+#define MT7925_TXV_GET_TX_FRMODE(_txv)\t(((_txv)[0] \u0026 (0x7 \u003c\u003c 8)) \u003e\u003e 8)\n+#define MT7925_TXV_GET_TX_MODE(_txv)\t(((_txv)[0] \u0026 (0xf \u003c\u003c 12)) \u003e\u003e 12)\n+#define MT7925_TXV_GET_TX_NSTS(_txv)\t(((_txv)[2] \u0026 (0xfU \u003c\u003c 28)) \u003e\u003e 28)\n+#define MT7925_TXV_GET_TX_PWR(_txv)\t(((_txv)[0] \u0026 (0xff \u003c\u003c 16)) \u003e\u003e 16)\n+#define MT7925_TXV_GET_TX_SGI(_txv)\t(((_txv)[1] \u0026 (0x3 \u003c\u003c 26)) \u003e\u003e 26)\n+#define MT7925_TXV_GET_TX_SPE_IDX(_txv)\t(((_txv)[0] \u0026 (0x1f \u003c\u003c 0)) \u003e\u003e 0)\n+#define MT7925_TXV_GET_TX_DCM(_txv)\t(((_txv)[2] \u0026 (0x1 \u003c\u003c 4)) \u003e\u003e 4)\n+#define MT7925_TXV_GET_TX_106T(_txv)\t(((_txv)[2] \u0026 (0x1 \u003c\u003c 5)) \u003e\u003e 5)\n+#define MT7925_TXV_RATE_UNMASK_DCM(_r)\t((u8)(_r) \u0026 0xef)\n+#define MT7925_TXV_RATE_UNMASK_106T(_r)\t((u8)(_r) \u0026 0xdf)\n+\n+extern const char * const mt7925_tx_mode_str[MT7925_TX_MODE_NUM];\n+extern const char * const mt7925_tx_rate_cck_str[MT7925_TX_RATE_CCK_NUM];\n+extern const char * const mt7925_tx_rate_bw_str[MT7925_TX_RATE_BW_NUM];\n+\n+/* TX rate mode, mirror Gen4m TX_RATE_MODE_* (see nic_rate.h). Used to decode\n+ * both the TX Vector BBP latch and the firmware auto-rate table rate codes.\n+ */\n+enum mt7925_tx_rate_mode {\n+\tMT7925_TX_RATE_MODE_CCK = 0,\n+\tMT7925_TX_RATE_MODE_OFDM = 1,\n+\tMT7925_TX_RATE_MODE_HTMIX = 2,\n+\tMT7925_TX_RATE_MODE_HTGF = 3,\n+\tMT7925_TX_RATE_MODE_VHT = 4,\n+\tMT7925_TX_RATE_MODE_PLR = 5,\n+\tMT7925_TX_RATE_MODE_HE_SU = 8,\n+\tMT7925_TX_RATE_MODE_HE_ER = 9,\n+\tMT7925_TX_RATE_MODE_HE_TRIG = 10,\n+\tMT7925_TX_RATE_MODE_HE_MU = 11,\n+\tMT7925_TX_RATE_MODE_EHT_ER = 13,\n+\tMT7925_TX_RATE_MODE_EHT_TRIG = 14,\n+\tMT7925_TX_RATE_MODE_EHT_MU = 15,\n+};\n+\n+enum {\n+\tUNI_CMD_MIB_DATA,\n+};\n+\n+enum stats_query_mib_array_index {\n+\tQUERY_MIB_CNT_RX_FCS_ERR = 0,\n+\tQUERY_MIB_CNT_RX_FIFO_OVERFLOW,\n+\tQUERY_MIB_CNT_RX_MPDU,\n+\tQUERY_MIB_CNT_AMPDU_RX_COUNT,\n+\tQUERY_MIB_CNT_PF_DROP,\n+\tQUERY_MIB_CNT_LEN_MISMATCH,\n+\tQUERY_MIB_CNT_CHANNEL_IDLE,\n+\tQUERY_MIB_CNT_CCA_NAV_TX_TIME,\n+\tQUERY_MIB_CNT_MDRDY,\n+\tQUERY_MIB_CNT_RX_CCK_MDRDY_TIME,\n+\tQUERY_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME,\n+\tQUERY_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME,\n+\tQUERY_MIB_CNT_P_CCA_TIME,\n+\tQUERY_MIB_CNT_S_CCA_TIME,\n+\tQUERY_MIB_CNT_P_ED_TIME,\n+\tQUERY_MIB_CNT_BCN_TX,\n+\tQUERY_MIB_CNT_TX_BW_40MHZ,\n+\tQUERY_MIB_CNT_TX_BW_80MHZ,\n+\tQUERY_MIB_CNT_TX_BW_160MHZ,\n+\tQUERY_MIB_CNT_BSS0_BA_MISS,\n+\tQUERY_MIB_CNT_BSS0_RTS_TX_CNT,\n+\tQUERY_MIB_CNT_BSS0_FRAME_RETRY,\n+\tQUERY_MIB_CNT_BSS0_FRAME_RETRY_2,\n+\tQUERY_MIB_CNT_BSS0_RTS_RETRY,\n+\tQUERY_MIB_CNT_BSS0_ACK_FAIL,\n+\tQUERY_MIB_CNT_AMPDU,\n+\tQUERY_MIB_CNT_AMPDU_MPDU,\n+\tQUERY_MIB_CNT_AMPDU_ACKED,\n+\tQUERY_MIB_CNT_MAX_NUM,\n+};\n+\n+enum stats_trx_agg_range {\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE0_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE1_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE2_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE3_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE4_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE5_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE6_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE7_IDX,\n+\tSTAT_MIB_CNT_TRX_AGG_RANGE_MAX_NUM\n+};\n+\n+enum {\n+\tMT7925_BW_20 = 0,\n+\tMT7925_BW_40,\n+\tMT7925_BW_80,\n+\tMT7925_BW_160,\n+};\n+\n+struct mt7925_sta_stats_ac {\n+\t__le32 tx_fail;\n+\t__le32 tx_retry;\n+} __packed;\n+\n+struct mt7925_sta_stats_tx_vector {\n+\t__le32 txv[3];\n+} __packed;\n+\n+struct mt7925_sta_stats_mib {\n+\t__le32 rx_mpdu_cnt;\n+\t__le32 fcs_error;\n+\t__le32 rx_fifo_full;\n+\t__le32 ampdu_tx_sf_cnt;\n+\t__le32 ampdu_tx_ack_sf_cnt;\n+\t__le32 tx_range_ampdu_cnt[MT7925_STA_STATS_AGG_RANGE_NUM];\n+} __packed;\n+\n+/* Firmware EVENT_STA_STATISTICS body. */\n+struct mt7925_sta_stats {\n+\tu8 version;\n+\tu8 rsv[3];\n+\t__le32 flags;\n+\n+\tu8 sta_idx;\n+\tu8 bss_idx;\n+\tu8 wtbl_idx;\n+\tu8 rsv1;\n+\n+\tu8 mac_addr[ETH_ALEN];\n+\tu8 per;\n+\tu8 rcpi;\n+\n+\t__le32 phy_mode;\n+\t__le16 link_speed; /* 0.5 Mbit/s units */\n+\tu8 link_quality;\n+\tu8 link_reserved;\n+\n+\t__le32 tx_count;\n+\t__le32 tx_fail_count;\n+\t__le32 tx_life_timeout_count;\n+\t__le32 tx_done_air_time;\n+\t__le32 transmit_count;\n+\t__le32 transmit_fail_count;\n+\n+\tstruct mt7925_sta_stats_ac ac[MT7925_STA_STATS_AC_NUM];\n+\n+\tu8 temperature;\n+\tu8 skip_ar;\n+\tu8 ar_table_idx;\n+\tu8 rate_entry_idx;\n+\tu8 rate_entry_idx_prev;\n+\tu8 tx_sgi_detect_pass_cnt;\n+\tu8 ave_per;\n+\tu8 rsv2;\n+\n+\t__le32 agg_range_ctrl[2];\n+\tu8 range_mode;\n+\tu8 rsv3[3];\n+\t__le32 agg_range_ctrl_ext[6];\n+\n+\tu8 ar_state_curr;\n+\tu8 ar_state_prev;\n+\tu8 ar_action_type;\n+\tu8 highest_rate_cnt;\n+\tu8 lowest_rate_cnt;\n+\tu8 rsv4;\n+\t__le16 train_up;\n+\t__le16 train_down;\n+\tu8 rsv5[2];\n+\t__le32 rate1_tx_cnt;\n+\t__le32 rate1_fail_cnt;\n+\n+\tstruct mt7925_sta_stats_tx_vector tx_vector[MT7925_STA_STATS_BAND_NUM];\n+\tstruct mt7925_sta_stats_mib mib[MT7925_STA_STATS_BAND_NUM];\n+\n+\tu8 is_force_tx_stream;\n+\tu8 is_force_se_off;\n+\t__le16 ra_running_cnt;\n+\tu8 ra_status;\n+\tu8 max_ampdu_factor;\n+\tu8 tx_quality[MT7925_STA_STATS_TX_QUALITY_NUM];\n+\tu8 tx_rate_up_penalty;\n+\tu8 low_traffic_mode;\n+\tu8 low_traffic_count;\n+\tu8 low_traffic_dashboard;\n+\tu8 dynamic_sgi_state;\n+\tu8 dynamic_sgi_score;\n+\tu8 dynamic_bw_state;\n+\tu8 dynamic_gband_256qam_state;\n+\tu8 vht_non_sp_rate_state;\n+\tu8 rsv6[3];\n+\tu8 rsv7[2];\n+} __packed;\n+\n+struct mt7925_sta_rec_lookup {\n+\tint sta_rec_idx;\n+};\n+\n+/* Firmware auto-rate table snapshot, mirror Gen4m struct UNI_EVENT_STAT_WTBL.\n+ *\n+ * The firmware RA maintains up to MT7925_AUTO_RATE_NUM candidate rates in\n+ * rate_code[]. rate_idx tells which entry is currently in use, so a dump can\n+ * point at it with \"--\u003e\". fcap is the bandwidth capability and the ldpc/sgi\n+ * flags describe the per-mode coding/guard-interval used for those rates.\n+ */\n+struct mt7925_wtbl_rate {\n+\t__le16 tag;\n+\t__le16 len;\n+\tu8 rx_rcpi0;\n+\tu8 rx_rcpi1;\n+\tu8 cbrn;\n+\tu8 fcap;\n+\tu8 spe_idx;\n+\tu8 g2;\t\t\t/* SGI enabled, non-HE, BW20 */\n+\tu8 g4;\t\t\t/* SGI enabled, non-HE, BW40 */\n+\tu8 g8;\t\t\t/* SGI enabled, non-HE, BW80 */\n+\tu8 g16;\t\t\t/* SGI enabled, non-HE, BW160 */\n+\tu8 g2_he;\t\t/* GI, HE, BW20 */\n+\tu8 g4_he;\t\t/* GI, HE, BW40 */\n+\tu8 g8_he;\t\t/* GI, HE, BW80 */\n+\tu8 g16_he;\t\t/* GI, HE, BW160 */\n+\tu8 gi_eht;\t\t/* GI, EHT */\n+\tu8 ht_ldpc;\n+\tu8 vht_ldpc;\n+\tu8 he_ldpc;\n+\tu8 eht_ldpc;\n+\tu8 af;\n+\tu8 rate_idx;\t\t/* index into rate_code[] currently in use */\n+\t__le16 rate_code[MT7925_AUTO_RATE_NUM];\n+\t__le32 rsv[4];\n+} __packed;\n+\n+int\n+mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx);\n+\n+void\n+mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3]);\n+\n+u8\n+mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap);\n+\n+u8\n+mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode);\n+\n+char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx);\n+\n+int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,\n+\t\t\t struct mt7925_wtbl_rate *rate);\n+\n+int mt792x_mcu_get_stat(struct mt792x_dev *dev,\n+\t\t\tstruct mt7925_sta_stats *stats);\n+\n+int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,\n+\t\t\t const u32 *counters, u8 counter_num,\n+\t\t\t u64 *values);\n+\n+/* GET_STAT_INFO (UNI_CMD_ID_GET_STATISTICS = 0x23),\n+ * sub-command UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1.\n+ *\n+ * @band_idx: band/BSS index (0..3)\n+ * @rssi: out, moving-average beacon RSSI (dBm), may be NULL\n+ * @tx_link_speed_kbps: out, TX link speed in kbit/s, may be NULL\n+ *\n+ * Returns 0 on success, -ENOENT if the band's link quality is not ready.\n+ *\n+ * NOTE: firmware provides only RSSI and TX rate here. RX rate/bandwidth are\n+ * not in this event; read wcid-\u003erate for the RX rate.\n+ */\n+int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,\n+\t\t\t\ts8 *rssi, u32 *tx_link_speed_kbps);\n+\n+#endif\n"
} |
| 2/1 | 2026/08/31 03:56 | agent | patch-evaluator |
1mModel:core Args: null Results: {
"EnableConfigs": [
"WLAN",
"WLAN_VENDOR_MEDIATEK",
"MAC80211",
"MT7925E",
"MT7925U",
"MT7925_COMMON",
"DEBUG_FS"
],
"FocusSymbols": [
"mt792x_stats",
"mt792x_mcu_get_stat",
"mt7925_mcu_get_mib_info",
"mt7925_mcu_get_link_quality",
"mt792x_mcu_get_wtbl_rate",
"mt7925_print_last_tx_rate",
"mt7925_get_ap_sta_rec_idx",
"mt7925_wtbl_get_sgi",
"mt7925_wtbl_get_ldpc"
],
"Reasoning": "The patch adds debugfs statistics support and associated MCU querying and TLV parsing logic (STA stats, MIB counters, link quality, WTBL auto-rate table, TX vector decode) for MediaTek MT7925 devices. These code paths contain parsing and formatting logic reachable via debugfs and USB device emulation.",
"WorthFuzzing": true
}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 d28e1a6c65afcbfa8b3c17b2f361b8ed61e44efc
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 31 03:56:29 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 0ededa569e9a5..bf0f105c786e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1483,6 +1483,179 @@ enum {
MT_NIC_CAP_EML_CAP = 0x22,
};
+enum {
+ UNI_CMD_ID_STATISTICS_BASIC = 0,
+ UNI_CMD_ID_STATISTICS_LINK_QUALITY = 1,
+ UNI_CMD_ID_STATISTICS_STA = 2,
+ UNI_CMD_ID_STATISTICS_BUG_REPORT = 3,
+ UNI_CMD_ID_STATISTICS_TX_STATS = 4,
+ UNI_CMD_ID_STATISTICS_ALL_STATS = 5,
+ UNI_CMD_ID_STATISTICS_EML_STATS = 6,
+ UNI_CMD_ID_STATISTICS_REGULAR_STATS = 7,
+ UNI_CMD_ID_STATISTICS_BSS_LINK_QUALITY = 8,
+ UNI_CMD_ID_STATISTICS_ML_CHNL_COND = 9,
+ UNI_CMD_ID_STATISTICS_WTBL = 10,
+ UNI_CMD_ID_STATISTICS_LINK_LAYER_STATS = 128,
+ UNI_CMD_ID_STATISTICS_PPDU_LATENCY = 129,
+ UNI_CMD_ID_STATISTICS_CURRENT_TX_RATE = 130,
+ UNI_CMD_ID_STATISTICS_SET_TX_BITRATE_MONITOR = 131,
+ UNI_CMD_ID_STATISTICS_GET_PREDICT_TX_BITRATE = 132,
+ UNI_CMD_ID_STATISTICS_SET_ATPS_TYPE_RATE_MODE = 133,
+ UNI_CMD_ID_STATISTICS_SET_BEACON_REPORT = 134,
+ UNI_CMD_ID_STATISTICS_BSS_CURRENT_TX_RATE = 135,
+ UNI_CMD_ID_STATISTICS_GET_BSS_PREDICT_TX_BITRATE = 136,
+ UNI_CMD_ID_STATISTICS_MAX_NUM
+};
+
+enum mt7925_mib_counter {
+ UNI_CMD_MIB_CNT_RX_FCS_ERR = 0,
+ UNI_CMD_MIB_CNT_RX_FIFO_OVERFLOW = 1,
+ UNI_CMD_MIB_CNT_RX_MPDU = 2,
+ UNI_CMD_MIB_CNT_AMPDU_RX_COUNT = 3,
+ UNI_CMD_MIB_CNT_RX_TOTAL_BYTE = 4,
+ UNI_CMD_MIB_CNT_RX_VALID_AMPDU_SF = 5,
+ UNI_CMD_MIB_CNT_RX_VALID_BYTE = 6,
+ UNI_CMD_MIB_CNT_CHANNEL_IDLE = 7,
+ UNI_CMD_MIB_CNT_VEC_DROP = 8,
+ UNI_CMD_MIB_CNT_DELIMITER_FAIL = 9,
+ UNI_CMD_MIB_CNT_VEC_MISMATCH = 10,
+ UNI_CMD_MIB_CNT_MDRDY = 11,
+ UNI_CMD_MIB_CNT_RX_CCK_MDRDY_TIME = 12,
+ UNI_CMD_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME = 13,
+ UNI_CMD_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME = 14,
+ UNI_CMD_MIB_CNT_PF_DROP = 15,
+ UNI_CMD_MIB_CNT_LEN_MISMATCH = 16,
+ UNI_CMD_MIB_CNT_P_CCA_TIME = 17,
+ UNI_CMD_MIB_CNT_S_CCA_TIME = 18,
+ UNI_CMD_MIB_CNT_CCA_NAV_TX_TIME = 19,
+ UNI_CMD_MIB_CNT_P_ED_TIME = 20,
+ UNI_CMD_MIB_CNT_BCN_TX = 21,
+ UNI_CMD_MIB_CNT_TX_BW_20MHZ = 22,
+ UNI_CMD_MIB_CNT_TX_BW_40MHZ = 23,
+ UNI_CMD_MIB_CNT_TX_BW_80MHZ = 24,
+ UNI_CMD_MIB_CNT_TX_BW_160MHZ = 25,
+ UNI_CMD_RMAC_CNT_OBSS_AIRTIME = 26,
+ UNI_CMD_RMAC_CNT_NONWIFI_AIRTIME = 27,
+ UNI_CMD_MIB_CNT_TX_DUR_CNT = 28,
+ UNI_CMD_MIB_CNT_RX_DUR_CNT = 29,
+ UNI_CMD_MIB_CNT_BA_CNT = 30,
+ UNI_CMD_MIB_CNT_MAC2PHY_TX_TIME = 31,
+ UNI_CMD_MIB_CNT_RX_OUT_OF_RANGE_COUNT = 32,
+ UNI_CMD_MIB_CNT_IBF_TX = 33,
+ UNI_CMD_MIB_CNT_EBF_TX = 34,
+ UNI_CMD_MIB_CNT_MUBF_TX = 35,
+ UNI_CMD_MIB_CNT_RX_BF_VHTFBK = 36,
+ UNI_CMD_MIB_CNT_RX_BF_HTFBK = 37,
+ UNI_CMD_MIB_CNT_RX_BF_HEFBK = 38,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_BFPOLL_TRI = 39,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_TRI = 40,
+ UNI_CMD_MIB_CNT_BFEE_RX_FBKCQI = 41,
+ UNI_CMD_MIB_CNT_BFEE_RX_NDP = 42,
+ UNI_CMD_MIB_CNT_RX_BF_IBF_UPT = 43,
+ UNI_CMD_MIB_CNT_RX_BF_EBF_UPT = 44,
+ UNI_CMD_MIB_CNT_BFEE_SP_ABORT = 45,
+ UNI_CMD_MIB_CNT_BFEE_TB_LEN_ERR = 46,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_MUTE = 47,
+ UNI_CMD_MIB_CNT_BFEE_TMAC_ABORT = 48,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_CPL = 49,
+ UNI_CMD_MIB_CNT_BFEE_COANT_BLKTX = 50,
+ UNI_CMD_MIB_CNT_BFEE_FBK_SEG = 51,
+ UNI_CMD_MIB_CNT_NAV_TIME = 52,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT1 = 53,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT0 = 54,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT3 = 55,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT2 = 56,
+ UNI_CMD_MIB_CNT_BSS0_RTS_TX_CNT = 57,
+ UNI_CMD_MIB_CNT_BSS1_RTS_TX_CNT = 58,
+ UNI_CMD_MIB_CNT_BSS2_RTS_TX_CNT = 59,
+ UNI_CMD_MIB_CNT_BSS3_RTS_TX_CNT = 60,
+ UNI_CMD_MIB_CNT_BSS0_RTS_RETRY = 61,
+ UNI_CMD_MIB_CNT_BSS1_RTS_RETRY = 62,
+ UNI_CMD_MIB_CNT_BSS2_RTS_RETRY = 63,
+ UNI_CMD_MIB_CNT_BSS3_RTS_RETRY = 64,
+ UNI_CMD_MIB_CNT_BSS0_BA_MISS = 65,
+ UNI_CMD_MIB_CNT_BSS1_BA_MISS = 66,
+ UNI_CMD_MIB_CNT_BSS2_BA_MISS = 67,
+ UNI_CMD_MIB_CNT_BSS3_BA_MISS = 68,
+ UNI_CMD_MIB_CNT_BSS0_ACK_FAIL = 69,
+ UNI_CMD_MIB_CNT_BSS1_ACK_FAIL = 70,
+ UNI_CMD_MIB_CNT_BSS2_ACK_FAIL = 71,
+ UNI_CMD_MIB_CNT_BSS3_ACK_FAIL = 72,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY = 73,
+ UNI_CMD_MIB_CNT_BSS1_FRAME_RETRY = 74,
+ UNI_CMD_MIB_CNT_BSS2_FRAME_RETRY = 75,
+ UNI_CMD_MIB_CNT_BSS3_FRAME_RETRY = 76,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_2 = 77,
+ UNI_CMD_MIB_CNT_BSS1_FRAME_RETRY_2 = 78,
+ UNI_CMD_MIB_CNT_BSS2_FRAME_RETRY_2 = 79,
+ UNI_CMD_MIB_CNT_BSS3_FRAME_RETRY_2 = 80,
+ UNI_CMD_MIB_CNT_RX_A1_SEARCH = 81,
+ UNI_CMD_MIB_CNT_RX_DROP_MPDU = 82,
+ UNI_CMD_MIB_CNT_RX_UNWANTED = 83,
+ UNI_CMD_MIB_CNT_RX_FCS_OK = 84,
+ UNI_CMD_MIB_CNT_SU_TX_OK = 85,
+ UNI_CMD_MIB_CNT_TX_FULL_BW = 86,
+ UNI_CMD_MIB_CNT_TX_AUTO_BW = 87,
+ UNI_CMD_MIB_CNT_CCA_SAMPLE_IDLE = 88,
+ UNI_CMD_MIB_CNT_CCA_SAMPLE_ACTIVE = 89,
+ UNI_CMD_MIB_CNT_CCA_TIME = 90,
+ UNI_CMD_MIB_CNT_S_20BW_CCA_TIME = 91,
+ UNI_CMD_MIB_CNT_S_40BW_CCA_TIME = 92,
+ UNI_CMD_MIB_CNT_S_80BW_CCA_TIME = 93,
+ UNI_CMD_MIB_CNT_S_160BW_CCA_TIME = 94,
+ UNI_CMD_MIB_CNT_S_P20BW_0_ED_TIME = 95,
+ UNI_CMD_MIB_CNT_S_P20BW_1_ED_TIME = 96,
+ UNI_CMD_MIB_CNT_S_P20BW_2_ED_TIME = 97,
+ UNI_CMD_MIB_CNT_S_P20BW_3_ED_TIME = 98,
+ UNI_CMD_MIB_CNT_S_P20BW_4_ED_TIME = 99,
+ UNI_CMD_MIB_CNT_S_P20BW_5_ED_TIME = 100,
+ UNI_CMD_MIB_CNT_S_P20BW_6_ED_TIME = 101,
+ UNI_CMD_MIB_CNT_S_P20BW_7_ED_TIME = 102,
+ UNI_CMD_MIB_CNT_S_P20BW_8_ED_TIME = 103,
+ UNI_CMD_MIB_CNT_S_P20BW_9_ED_TIME = 104,
+ UNI_CMD_MIB_CNT_S_P20BW_10_ED_TIME = 105,
+ UNI_CMD_MIB_CNT_S_P20BW_11_ED_TIME = 106,
+ UNI_CMD_MIB_CNT_S_P20BW_12_ED_TIME = 107,
+ UNI_CMD_MIB_CNT_S_P20BW_13_ED_TIME = 108,
+ UNI_CMD_MIB_CNT_S_P20BW_14_ED_TIME = 109,
+ UNI_CMD_MIB_CNT_S_P20BW_15_ED_TIME = 110,
+ UNI_CMD_MIB_CNT_TX_BW_320MHZ = 111,
+ UNI_CMD_MIB_CNT_TX_DDLMT_RNG0 = 112, /* Rng0~Rng4 112~116 */
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_3 = 117, /* 117~120 */
+ UNI_CMD_MIB_CNT_BSS0_TX = 121, /* 121~124 */
+ UNI_CMD_MIB_CNT_BSS0_TX_DATA = 125, /* 125~128 */
+ UNI_CMD_MIB_CNT_BSS0_TX_BYTE = 129, /* 129~132 */
+ UNI_CMD_MIB_CNT_RX_OK_BSS0 = 133, /* 133~136 */
+ UNI_CMD_MIB_CNT_RX_BYTE_BSS0 = 137, /* 137~140 */
+ UNI_CMD_MIB_CNT_RX_DATA_BSS0 = 141, /* 141~144 */
+ UNI_CMD_MIB_CNT_MBSS0_TX_OK = 145, /* 145~160 */
+ UNI_CMD_MIB_CNT_MBSS0_TX_BYTE = 161, /* 161~176 */
+ UNI_CMD_MIB_CNT_RX_OK_MBSS0 = 177, /* 177~192 */
+ UNI_CMD_MIB_CNT_RX_BYTE_MBSS0 = 193, /* 193~208 */
+ UNI_CMD_MIB_CNT_AMPDU = 209,
+ UNI_CMD_MIB_CNT_AMPDU_MPDU = 210,
+ UNI_CMD_MIB_CNT_AMPDU_ACKED = 211,
+ UNI_CMD_MIB_CNT_MAX_NUM
+};
+
+enum ENUM_UNI_CMD_GET_STATISTICS_TAG {
+ UNI_CMD_GET_STATISTICS_TAG_BASIC = 0,
+ UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1,
+ UNI_CMD_GET_STATISTICS_TAG_STA = 2,
+ UNI_CMD_GET_STATISTICS_TAG_BUG_REPORT = 3,
+ UNI_CMD_GET_STATISTICS_TAG_EML_STATS = 6,
+ UNI_CMD_GET_STATISTICS_TAG_REGULAR_STATS = 7,
+ UNI_CMD_GET_STATISTICS_TAG_BSS_LINK_QUALITY = 8,
+ UNI_CMD_GET_STATISTICS_TAG_GET_ML_CHNL_COND = 9,
+ UNI_CMD_GET_STATISTICS_TAG_STAT_WTBL = 10,
+ UNI_CMD_GET_STATISTICS_TAG_LINK_LAYER_STATS = 0x80,
+ UNI_CMD_GET_STATISTICS_TAG_PPDU_LATENCY,
+ UNI_CMD_GET_STATISTICS_TAG_CURRENT_TX_RATE,
+ UNI_CMD_GET_STATISTICS_TAG_BEACON_REPORT = 0x86,
+ UNI_CMD_GET_STATISTICS_TAG_BSS_CURRENT_TX_RATE = 0x87,
+ UNI_CMD_GET_STATISTICS_TAG_BSS_PRED_TX_BITRATE = 0x88,
+};
+
#define UNI_WOW_DETECT_TYPE_MAGIC BIT(0)
#define UNI_WOW_DETECT_TYPE_ANY BIT(1)
#define UNI_WOW_DETECT_TYPE_DISCONNECT BIT(2)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile
index f9dcc0bba393c..3863a89b89742 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_MT7925_COMMON) += mt7925-common.o
obj-$(CONFIG_MT7925E) += mt7925e.o
obj-$(CONFIG_MT7925U) += mt7925u.o
-mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o
+mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o stats.o
mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7925e-y := pci.o pci_mac.o pci_mcu.o
mt7925u-y := usb.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
index d01ff49de47af..ace501049792e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
@@ -1,8 +1,11 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/* Copyright (C) 2023 MediaTek Inc. */
+#include <linux/math64.h>
+
#include "mt7925.h"
#include "mcu.h"
+#include "stats.h"
static int
mt7925_reg_set(void *data, u64 val)
@@ -286,6 +289,366 @@ static int mt7925_chip_reset(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, "%lld\n");
+static const u32 stats_query_mib_counters[] = {
+ UNI_CMD_MIB_CNT_RX_FCS_ERR,
+ UNI_CMD_MIB_CNT_RX_FIFO_OVERFLOW,
+ UNI_CMD_MIB_CNT_RX_MPDU,
+ UNI_CMD_MIB_CNT_AMPDU_RX_COUNT,
+ UNI_CMD_MIB_CNT_PF_DROP,
+ UNI_CMD_MIB_CNT_LEN_MISMATCH,
+ UNI_CMD_MIB_CNT_CHANNEL_IDLE,
+ UNI_CMD_MIB_CNT_CCA_NAV_TX_TIME,
+ UNI_CMD_MIB_CNT_MDRDY,
+ UNI_CMD_MIB_CNT_RX_CCK_MDRDY_TIME,
+ UNI_CMD_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME,
+ UNI_CMD_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME,
+ UNI_CMD_MIB_CNT_P_CCA_TIME,
+ UNI_CMD_MIB_CNT_S_CCA_TIME,
+ UNI_CMD_MIB_CNT_P_ED_TIME,
+ UNI_CMD_MIB_CNT_BCN_TX,
+ UNI_CMD_MIB_CNT_TX_BW_40MHZ,
+ UNI_CMD_MIB_CNT_TX_BW_80MHZ,
+ UNI_CMD_MIB_CNT_TX_BW_160MHZ,
+ UNI_CMD_MIB_CNT_BSS0_BA_MISS,
+ UNI_CMD_MIB_CNT_BSS0_RTS_TX_CNT,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_2,
+ UNI_CMD_MIB_CNT_BSS0_RTS_RETRY,
+ UNI_CMD_MIB_CNT_BSS0_ACK_FAIL,
+ UNI_CMD_MIB_CNT_AMPDU,
+ UNI_CMD_MIB_CNT_AMPDU_MPDU,
+ UNI_CMD_MIB_CNT_AMPDU_ACKED,
+};
+
+/* Dump the whole firmware auto-rate table and mark the entry currently in use
+ * with "-->"
+ */
+static void
+mt7925_dump_auto_rate_table(struct seq_file *s,
+ const struct mt7925_wtbl_rate *wr)
+{
+ u8 fcap = wr->fcap;
+ u8 rate_idx = wr->rate_idx;
+ u8 cbrn = wr->cbrn;
+ int i;
+
+ seq_printf(s, "%-22s Cur Rate Index = %u\n", " ", rate_idx);
+
+ for (i = 0; i < MT7925_AUTO_RATE_NUM; i++) {
+ u16 rate_code = le16_to_cpu(wr->rate_code[i]);
+ u8 txmode = MT7925_HW_RATE_TO_MODE(rate_code);
+ u8 rate = MT7925_HW_RATE_TO_MCS(rate_code);
+ u8 nsts = MT7925_HW_RATE_TO_NSS(rate_code) + 1;
+ u8 stbc = MT7925_HW_RATE_TO_STBC(rate_code);
+ u8 dcm = MT7925_HW_RATE_TO_DCM(rate_code);
+ u8 ersu106t = MT7925_HW_RATE_TO_106T(rate_code);
+ u8 sgi = mt7925_wtbl_get_sgi(wr, txmode, fcap);
+ u8 ldpc = mt7925_wtbl_get_ldpc(wr, txmode);
+ const char *mode_str = "N/A";
+
+ if (dcm)
+ rate = MT7925_HW_RATE_UNMASK_DCM(rate);
+ if (ersu106t)
+ rate = MT7925_HW_RATE_UNMASK_106T(rate);
+
+ if (txmode < ARRAY_SIZE(mt7925_tx_mode_str))
+ mode_str = mt7925_tx_mode_str[txmode];
+
+ seq_printf(s, "Rate index[%d] %s", i,
+ rate_idx == i ? "--> " : " ");
+
+ /* rate/MCS field */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ",
+ mt7925_tx_rate_cck_str[rate & 0x3]);
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ seq_printf(s, "%s, ", mt7925_hw_rate_ofdm_str(rate));
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF)
+ seq_printf(s, "MCS%d, ", rate);
+ else
+ seq_printf(s, "%s%d_MCS%d, ",
+ stbc ? "NSTS" : "NSS", nsts, rate);
+
+ /* bandwidth: mirror the CCK/OFDM -> BW20 and cbrn handling */
+ if (txmode == MT7925_TX_RATE_MODE_CCK ||
+ txmode == MT7925_TX_RATE_MODE_OFDM)
+ seq_printf(s, "%s, ", mt7925_tx_rate_bw_str[0]);
+ else if (i > cbrn)
+ seq_printf(s, "%s, ",
+ fcap < 5 ?
+ (fcap > MT7925_BW_20 ?
+ mt7925_tx_rate_bw_str[fcap - 1] :
+ mt7925_tx_rate_bw_str[fcap]) :
+ mt7925_tx_rate_bw_str[5]);
+ else
+ seq_printf(s, "%s, ",
+ fcap < 5 ? mt7925_tx_rate_bw_str[fcap] :
+ mt7925_tx_rate_bw_str[5]);
+
+ /* GI / preamble */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ", rate < 4 ? "LP" : "SP");
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ ; /* OFDM has no GI/preamble to print */
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF ||
+ txmode == MT7925_TX_RATE_MODE_VHT ||
+ txmode == MT7925_TX_RATE_MODE_PLR)
+ seq_printf(s, "%s, ", sgi == 0 ? "LGI" : "SGI");
+ else
+ seq_printf(s, "%s, ",
+ sgi == 0 ? "SGI" :
+ (sgi == 1 ? "MGI" : "LGI"));
+
+ /* mode, DCM, 106t, STBC, coding */
+ seq_printf(s, "%s%s%s%s%s\n",
+ mode_str,
+ dcm ? ", DCM" : "", ersu106t ? ", 106t" : "",
+ stbc ? ", STBC, " : ", ",
+ (ldpc == 0 ||
+ txmode == MT7925_TX_RATE_MODE_CCK ||
+ txmode == MT7925_TX_RATE_MODE_OFDM) ?
+ "BCC" : "LDPC");
+ }
+}
+
+static int mt792x_stats(struct seq_file *s, void *data)
+{
+ s8 rssi = 0;
+ u8 band_idx = 0;
+ bool wtbl_rate_valid = false;
+ int ret = 0;
+ int i = 0;
+ u32 stats_value = 0;
+ u32 tx_link_speed_kbps = 0;
+ u32 tx_per_rem = 0;
+ __le32 tx_ampdu_cnt = 0;
+ u64 tx_total = 0;
+ u64 tx_fail = 0;
+ u64 tx_per = 0;
+ /* UNI_CMD_MIB_DATA */
+ u64 mib_values[ARRAY_SIZE(stats_query_mib_counters)];
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
+ struct mt7925_wtbl_rate wtbl_rate;
+ struct mt7925_sta_stats *stats = NULL;
+
+ band_idx = dev->mphy.band_idx;
+
+ if (band_idx >= MT7925_STA_STATS_BAND_NUM)
+ return -EINVAL;
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats)
+ return -ENOMEM;
+
+ /* Get STA_STATS */
+ mt792x_mutex_acquire(dev);
+ ret = mt792x_mcu_get_stat(dev, stats);
+ mt792x_mutex_release(dev);
+ if (ret)
+ goto out;
+
+ /* Get MIB_STATS */
+ mt792x_mutex_acquire(dev);
+ ret = mt7925_mcu_get_mib_info(dev,
+ band_idx,
+ stats_query_mib_counters,
+ ARRAY_SIZE(stats_query_mib_counters),
+ mib_values);
+ mt792x_mutex_release(dev);
+ if (ret)
+ goto out;
+
+ /* Get Link_Speed and RSSI */
+ mt792x_mutex_acquire(dev);
+ ret = mt7925_mcu_get_link_quality(dev,
+ stats->bss_idx,
+ &rssi,
+ &tx_link_speed_kbps);
+ mt792x_mutex_release(dev);
+ if (ret)
+ goto out;
+
+ /* Get the firmware auto-rate table (best effort; do not abort the
+ * whole stats dump if the WTBL query is not available).
+ */
+ mt792x_mutex_acquire(dev);
+ if (!mt792x_mcu_get_wtbl_rate(dev, stats->wtbl_idx, &wtbl_rate))
+ wtbl_rate_valid = true;
+ mt792x_mutex_release(dev);
+
+ /* Print STA_STATS info */
+ seq_printf(s, "(STA) connected AP MAC Address = %pM\n",
+ stats->mac_addr);
+ seq_printf(s, "%-22s BssIdx = [%u]\n", " ", stats->bss_idx);
+ seq_printf(s, "%-22s StaRecIdx = [%u]\n",
+ " ", stats->sta_idx);
+ seq_printf(s, "%-22s RSSI = %d\n", " ", rssi);
+ seq_printf(s, "%-22s Link_Speed = %u (kbit/s)\n",
+ " ", tx_link_speed_kbps);
+
+ seq_printf(s, "%-22s temperature = %u\n",
+ " ", stats->temperature);
+
+ stats_value = le32_to_cpu(stats->transmit_count) -
+ le32_to_cpu(stats->transmit_fail_count);
+ seq_printf(s, "%-22s Tx success = %u\n",
+ " ", stats_value);
+
+ stats_value = le32_to_cpu(stats->tx_fail_count) -
+ le32_to_cpu(stats->tx_life_timeout_count);
+ seq_printf(s, "%-22s Tx fail to Rcv ACK after retry = %u\n",
+ " ", stats_value);
+
+ seq_printf(s, "%-22s Rx Mpdu = %u\n",
+ " ", le32_to_cpu(stats->mib[band_idx].rx_mpdu_cnt));
+
+ seq_printf(s, "%-22s Rx Fcs Error = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].fcs_error));
+ seq_printf(s, "%-22s Rx FIFO full = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].rx_fifo_full));
+
+ for (i = 0; i < STAT_MIB_CNT_TRX_AGG_RANGE_MAX_NUM; i++) {
+ tx_ampdu_cnt = stats->mib[band_idx].tx_range_ampdu_cnt[i];
+ seq_printf(s, "%-22s TRX_AGG_RANGE[%d] = %u (PPDU)\n",
+ " ",
+ i,
+ le32_to_cpu(tx_ampdu_cnt));
+ }
+
+ seq_printf(s, "%-22s MPDUs in AMPDUs transmitted = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].ampdu_tx_sf_cnt));
+ seq_printf(s, "%-22s MPDUs in AMPDUs transmitted with ACK reply = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].ampdu_tx_ack_sf_cnt));
+ seq_printf(s, "%-22s rate1_tx_cnt = %u\n",
+ " ", le32_to_cpu(stats->rate1_tx_cnt));
+ seq_printf(s, "%-22s rate1_fail_cnt = %u\n",
+ " ", le32_to_cpu(stats->rate1_fail_cnt));
+ seq_printf(s, "%-22s train_up = %u\n",
+ " ", le16_to_cpu(stats->train_up));
+ seq_printf(s, "%-22s train_down = %u\n",
+ " ", le16_to_cpu(stats->train_down));
+ seq_printf(s, "%-22s is_force_tx_stream = %u\n",
+ " ", stats->is_force_tx_stream);
+ seq_printf(s, "%-22s is_force_se_off = %u\n",
+ " ", stats->is_force_se_off);
+ seq_printf(s, "%-22s max_ampdu_factor = %u\n",
+ " ", stats->max_ampdu_factor);
+ seq_printf(s, "%-22s tx_rate_up_penalty = %u\n",
+ " ", stats->tx_rate_up_penalty);
+ seq_printf(s, "%-22s low_traffic_mode = %u\n",
+ " ", stats->low_traffic_mode);
+ seq_printf(s, "%-22s low_traffic_count = %u\n",
+ " ", stats->low_traffic_count);
+ seq_printf(s, "%-22s low_traffic_dashboard = %u\n",
+ " ", stats->low_traffic_dashboard);
+ seq_printf(s, "%-22s dynamic_sgi_state = %u\n",
+ " ", stats->dynamic_sgi_state);
+ seq_printf(s, "%-22s dynamic_sgi_score = %u\n",
+ " ", stats->dynamic_sgi_score);
+ seq_printf(s, "%-22s dynamic_bw_state = %u\n",
+ " ", stats->dynamic_bw_state);
+ seq_printf(s, "%-22s dynamic_gband_256qam_state = %u\n",
+ " ", stats->dynamic_gband_256qam_state);
+ seq_printf(s, "%-22s vht_non_sp_rate_state = %u\n",
+ " ", stats->vht_non_sp_rate_state);
+
+ /* Decode the TX Vector BBP latch to show the current TX MCS rate */
+ mt7925_print_last_tx_rate(s, stats->tx_vector[band_idx].txv);
+
+ /* Dump the whole firmware auto-rate table
+ * and mark the entry currently in use.
+ */
+ if (wtbl_rate_valid)
+ mt7925_dump_auto_rate_table(s, &wtbl_rate);
+
+ seq_puts(s, "\nmib state:\n");
+ /* ===Rx Related Counters=== */
+ seq_puts(s, "=== Rx Related Counters ===\n");
+ seq_printf(s, "%-22s Rx with CRC = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_FCS_ERR]);
+ seq_printf(s, "%-22s Rx drop due to out of resource = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_FIFO_OVERFLOW]);
+ seq_printf(s, "%-22s Rx Mpdu = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_MPDU]);
+ seq_printf(s, "%-22s Rx AMpdu = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU_RX_COUNT]);
+ seq_printf(s, "%-22s Rx PF Drop = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_PF_DROP]);
+ seq_printf(s, "%-22s Rx Len Mismatch = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_LEN_MISMATCH]);
+
+ /* ===Phy/Timing Related Counters=== */
+ seq_puts(s, "\n=== Phy/Timing Related Counters ===\n");
+ seq_printf(s, "%-22s ChannelIdleCnt = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_CHANNEL_IDLE]);
+ seq_printf(s, "%-22s CCA_NAV_Tx_Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_CCA_NAV_TX_TIME]);
+ seq_printf(s, "%-22s Rx_MDRDY_CNT = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_MDRDY]);
+ seq_printf(s, "%-22s CCK_MDRDY = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_CCK_MDRDY_TIME]);
+ seq_printf(s, "%-22s OFDM_MDRDY = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME]);
+ seq_printf(s, "%-22s OFDM_GREEN_MDRDY = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME]);
+ seq_printf(s, "%-22s Prim CCA Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_P_CCA_TIME]);
+ seq_printf(s, "%-22s Sec CCA Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_S_CCA_TIME]);
+ seq_printf(s, "%-22s Prim ED Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_P_ED_TIME]);
+
+ /* ===Tx Related Counters(Generic)=== */
+ seq_puts(s, "\n=== Tx Related Counters(Generic) ===\n");
+ seq_printf(s, "%-22s BeaconTxCnt = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_BCN_TX]);
+ seq_printf(s, "%-22s Tx 40MHz Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_TX_BW_40MHZ]);
+ seq_printf(s, "%-22s Tx 80MHz Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_TX_BW_80MHZ]);
+ seq_printf(s, "%-22s Tx 160MHz Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_TX_BW_160MHZ]);
+
+ /* ===BSSID[0] Related Counters=== */
+ seq_puts(s, "\n=== BSSID[0] Related Counters ===\n");
+ seq_printf(s, "%-22s BA Miss Cnt = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_BA_MISS]);
+ seq_printf(s, "%-22s RTS Tx Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_RTS_TX_CNT]);
+ seq_printf(s, "%-22s Frame Retry Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_FRAME_RETRY]);
+ seq_printf(s, "%-22s Frame Retry 2 Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_FRAME_RETRY_2]);
+ seq_printf(s, "%-22s RTS Retry Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_RTS_RETRY]);
+ seq_printf(s, "%-22s Ack Failed Cnt = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_ACK_FAIL]);
+
+ /* ===AMPDU Related Counters=== */
+ seq_puts(s, "\n=== AMPDU Related Counters ===\n");
+ seq_printf(s, "%-22s Tx AMPDU_Pkt_Cnt = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU]);
+ seq_printf(s, "%-22s Tx AMPDU_MPDU_Pkt_Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU_MPDU]);
+ seq_printf(s, "%-22s AMPDU Tx success = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU_ACKED]);
+
+ tx_total = mib_values[QUERY_MIB_CNT_AMPDU_MPDU];
+ tx_fail = mib_values[QUERY_MIB_CNT_AMPDU_MPDU] -
+ mib_values[QUERY_MIB_CNT_AMPDU_ACKED];
+ tx_per = tx_total == 0 ? 0 : div64_u64(1000 * tx_fail, tx_total);
+ seq_printf(s, "%-22s AMPDU Tx fail count = %llu (MPDU), PER=%llu.%1llu%%\n",
+ " ",
+ tx_fail,
+ div_u64_rem(tx_per, 10, &tx_per_rem), (u64)tx_per_rem);
+
+out:
+ kfree(stats);
+ return ret;
+}
+
int mt7925_init_debugfs(struct mt792x_dev *dev)
{
struct dentry *dir;
@@ -313,5 +676,8 @@ int mt7925_init_debugfs(struct mt792x_dev *dev)
mt792x_pm_stats);
debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "stats", dir,
+ mt792x_stats);
+
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/stats.c b/drivers/net/wireless/mediatek/mt76/mt7925/stats.c
new file mode 100644
index 0000000000000..874c0b979c264
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/stats.c
@@ -0,0 +1,587 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/* Copyright (C) 2026 MediaTek Inc. */
+
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include "mt7925.h"
+#include "mcu.h"
+#include "mac.h"
+#include "stats.h"
+
+#define MT7925_STA_STATS_VERSION 1
+#define MT7925_STA_STATS_VALID 1U
+
+#define MT7925_MIB_MAX_CNT 32
+
+/* firmware UNI_CMD_MIB_CNT_MAX_NUM upper bound */
+#define MT7925_MIB_CNT_MAX_NUM 512
+
+#define MT7925_LQ_BAND_NUM 4 /* Link quality band */
+
+const char * const mt7925_tx_mode_str[] = {
+ "CCK", "OFDM", "MM", "GF", "VHT", "PLR",
+ "PLRP", "ALR", "HE_SU", "HE_ER", "HE_TRIG", "HE_MU",
+ "EHT_ER", "TOF", "EHT_TRIG", "EHT_MU"
+};
+
+const char * const mt7925_tx_rate_cck_str[] = {
+ "1M", "2M", "5.5M", "11M", "N/A"
+};
+
+const char * const mt7925_tx_rate_bw_str[] = {
+ "BW20", "BW40", "BW80", "BW160/BW8080", "BW320", "N/A"
+};
+
+struct mt7925_sta_stats_req {
+ u8 rsv[4];
+ __le16 tag;
+ __le16 len;
+ u8 sta_rec_idx;
+ u8 rsv1;
+ u8 lls_read_clear;
+ u8 reset_counter;
+} __packed;
+
+struct mt7925_sta_stats_event {
+ u8 rsv[4];
+ __le16 tag;
+ __le16 len;
+ struct mt7925_sta_stats stats;
+} __packed;
+
+/* WTBL auto-rate request TLV, mirror Gen4m struct UNI_CMD_STAT_WTBL.
+ * The RA tag reuses UNI_CMD_ID_STATISTICS_WTBL (10).
+ */
+struct mt7925_wtbl_rate_req {
+ u8 rsv[4];
+ __le16 tag;
+ __le16 len;
+ __le16 wlan_idx;
+ __le16 rsv1;
+} __packed;
+
+/* WTBL auto-rate event TLV. Firmware answers cmd tag 10 with event tag 12. */
+struct mt7925_wtbl_rate_event {
+ u8 rsv[4];
+ struct mt7925_wtbl_rate rate;
+} __packed;
+
+/* fixed field, mirror UNI_(CMD|EVENT)_MIB_INFO */
+struct mt7925_mib_hdr {
+ u8 band_idx;
+ u8 rsv[3];
+} __packed;
+
+/* One requested/returned MIB counter, mirror UNI_(CMD|EVENT)_MIB_DATA_T. */
+struct mt7925_mib_data {
+ __le16 tag; /* UNI_(CMD|EVENT)_MIB_DATA = 0 */
+ __le16 len;
+ __le32 counter; /* MIB counter ID (enum mt7925_mib_counter) */
+ __le64 data; /* only valid on event; ignored on cmd */
+} __packed;
+
+/* per-band link quality entry, mirror UNI_LINK_QUALITY */
+struct mt7925_link_quality {
+ s8 rssi; /* moving-average beacon RSSI of connected AP */
+ s8 link_quality; /* always 0 */
+ __le16 link_speed; /* TX rate1, unit 500 Kb/s */
+ u8 medium_busy_pct; /* always 0 */
+ u8 is_ready; /* 0: fields invalid, 1: valid */
+ u8 rsv[2];
+} __packed;
+
+/* request TLV, mirror UNI_CMD_LINK_QUALITY (header + tag/len only) */
+struct mt7925_lq_req {
+ u8 rsv[4]; /* UNI_CMD_GET_STATISTICS fixed field */
+ __le16 tag; /* UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1 */
+ __le16 len;
+} __packed;
+
+/* event TLV, mirror UNI_EVENT_LINK_QUALITY */
+struct mt7925_lq_event {
+ u8 rsv[4]; /* UNI_EVENT_STATISTICS fixed field */
+ __le16 tag; /* UNI_EVENT_ID_STATISTICS_LINK_QUALITY = 1 */
+ __le16 len;
+ struct mt7925_link_quality lq[MT7925_LQ_BAND_NUM];
+} __packed;
+
+static void
+mt7925_get_ap_sta_rec_idx_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mt7925_sta_rec_lookup *lookup = data;
+ struct mt792x_vif *mvif;
+ struct mt792x_sta *msta;
+
+ if (lookup->sta_rec_idx >= 0)
+ return;
+
+ if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
+ return;
+
+ mvif = (struct mt792x_vif *)vif->drv_priv;
+ msta = mvif->wep_sta;
+ if (!msta)
+ return;
+
+ if (!msta->deflink.wcid.sta)
+ return;
+
+ lookup->sta_rec_idx = msta->deflink.wcid.idx;
+}
+
+int
+mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx)
+{
+ struct mt7925_sta_rec_lookup lookup = {
+ .sta_rec_idx = -1,
+ };
+
+ lockdep_assert_held(&dev->mt76.mutex);
+
+ ieee80211_iterate_active_interfaces(dev->mphy.hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7925_get_ap_sta_rec_idx_iter,
+ &lookup);
+
+ if (lookup.sta_rec_idx < 0)
+ return -ENOTCONN;
+
+ if (lookup.sta_rec_idx > U8_MAX)
+ return -ERANGE;
+
+ *sta_rec_idx = lookup.sta_rec_idx;
+
+ return 0;
+}
+
+/* Decode the TX Vector BBP latch and print the last TX rate */
+void
+mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3])
+{
+ const char *mode_str = "N/A";
+ u8 rate, txmode, frmode, sgi, ldpc, nsts, stbc, spe, dcm, ersu106t;
+ s8 txpwr, pos_txpwr;
+ u32 txv[3];
+
+ txv[0] = le32_to_cpu(le_txv[0]);
+ txv[1] = le32_to_cpu(le_txv[1]);
+ txv[2] = le32_to_cpu(le_txv[2]);
+
+ if (txv[0] == 0xffffffff) {
+ seq_printf(s, "%-22s %s = %s\n", " ", "Last TX Rate", "N/A");
+ seq_printf(s, "%-22s %s = %s\n",
+ " ", "Chip Out TX Power", "N/A");
+ return;
+ }
+
+ rate = MT7925_TXV_GET_TX_RATE(txv);
+ txmode = MT7925_TXV_GET_TX_MODE(txv);
+ frmode = MT7925_TXV_GET_TX_FRMODE(txv);
+ nsts = MT7925_TXV_GET_TX_NSTS(txv) + 1;
+ sgi = MT7925_TXV_GET_TX_SGI(txv);
+ ldpc = MT7925_TXV_GET_TX_LDPC(txv);
+ stbc = MT7925_TXV_GET_TX_STBC(txv);
+ txpwr = MT7925_TXV_GET_TX_PWR(txv);
+ spe = MT7925_TXV_GET_TX_SPE_IDX(txv);
+ dcm = MT7925_TXV_GET_TX_DCM(txv);
+ ersu106t = MT7925_TXV_GET_TX_106T(txv);
+
+ if (dcm)
+ rate = MT7925_TXV_RATE_UNMASK_DCM(rate);
+ if (ersu106t)
+ rate = MT7925_TXV_RATE_UNMASK_106T(rate);
+
+ if (txmode < ARRAY_SIZE(mt7925_tx_mode_str))
+ mode_str = mt7925_tx_mode_str[txmode];
+
+ seq_printf(s, "%-22s %s = ", " ", "Last TX Rate");
+
+ /* rate/MCS field */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ",
+ rate < 4 ? mt7925_tx_rate_cck_str[rate] :
+ (((rate >= 5) && (rate <= 7)) ?
+ mt7925_tx_rate_cck_str[rate - 4] :
+ mt7925_tx_rate_cck_str[4]));
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ seq_printf(s, "%s, ", mt7925_hw_rate_ofdm_str(rate));
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF)
+ seq_printf(s, "MCS%d, ", rate);
+ else
+ seq_printf(s, "%s%d_MCS%d, ",
+ stbc ? "NSTS" : "NSS", nsts, rate);
+
+ /* bandwidth */
+ seq_printf(s, "%s, ",
+ frmode < 5 ? mt7925_tx_rate_bw_str[frmode] :
+ mt7925_tx_rate_bw_str[5]);
+
+ /* GI / preamble */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ", rate < 4 ? "LP" : "SP");
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ ; /* OFDM has no GI/preamble to print */
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF ||
+ txmode == MT7925_TX_RATE_MODE_VHT ||
+ txmode == MT7925_TX_RATE_MODE_PLR)
+ seq_printf(s, "%s, ", sgi == 0 ? "LGI" : "SGI");
+ else
+ seq_printf(s, "%s, ",
+ sgi == 0 ? "SGI" : (sgi == 1 ? "MGI" : "LGI"));
+
+ /* mode, DCM, 106t, STBC, coding, SPE */
+ seq_printf(s, "%s%s%s%s%s%s%d\n",
+ mode_str,
+ dcm ? ", DCM" : "", ersu106t ? ", 106t" : "",
+ stbc ? ", STBC, " : ", ", ldpc == 0 ? "BCC" : "LDPC",
+ ", SPE", spe);
+
+ /* chip out TX power (unit: 0.5 dBm) */
+ pos_txpwr = (txpwr < 0) ? (~txpwr + 1) : txpwr;
+ seq_printf(s, "%-22s %s = %c%d.%1d dBm\n",
+ " ", "Chip Out TX Power",
+ (txpwr < 0) ? '-' : '+',
+ (pos_txpwr / 2), 5 * (pos_txpwr % 2));
+}
+
+/* Guard interval used for the auto-rate entries, mirror Gen4m
+ * connac3x_get_sgi_info_from_fw(): pick the per-mode/per-BW flag.
+ */
+u8
+mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap)
+{
+ bool he = (txmode == MT7925_TX_RATE_MODE_HE_SU ||
+ txmode == MT7925_TX_RATE_MODE_HE_ER ||
+ txmode == MT7925_TX_RATE_MODE_HE_TRIG ||
+ txmode == MT7925_TX_RATE_MODE_HE_MU);
+ bool eht = (txmode == MT7925_TX_RATE_MODE_EHT_ER ||
+ txmode == MT7925_TX_RATE_MODE_EHT_TRIG ||
+ txmode == MT7925_TX_RATE_MODE_EHT_MU);
+
+ if (eht)
+ return wr->gi_eht;
+
+ switch (fcap) {
+ case MT7925_BW_20:
+ return he ? wr->g2_he : wr->g2;
+ case MT7925_BW_40:
+ return he ? wr->g4_he : wr->g4;
+ case MT7925_BW_80:
+ return he ? wr->g8_he : wr->g8;
+ case MT7925_BW_160:
+ return he ? wr->g16_he : wr->g16;
+ default:
+ return 0;
+ }
+}
+
+/* Coding used for the auto-rate entries, mirror Gen4m
+ * connac3x_wtbl_get_ldpc_info_from_fw(): 0 = BCC, 1 = LDPC.
+ */
+u8
+mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode)
+{
+ switch (txmode) {
+ case MT7925_TX_RATE_MODE_HTMIX:
+ case MT7925_TX_RATE_MODE_HTGF:
+ return wr->ht_ldpc;
+ case MT7925_TX_RATE_MODE_VHT:
+ return wr->vht_ldpc;
+ case MT7925_TX_RATE_MODE_HE_SU:
+ case MT7925_TX_RATE_MODE_HE_ER:
+ case MT7925_TX_RATE_MODE_HE_TRIG:
+ case MT7925_TX_RATE_MODE_HE_MU:
+ return wr->he_ldpc;
+ case MT7925_TX_RATE_MODE_EHT_ER:
+ case MT7925_TX_RATE_MODE_EHT_TRIG:
+ case MT7925_TX_RATE_MODE_EHT_MU:
+ return wr->eht_ldpc;
+ default:
+ return 0;
+ }
+}
+
+int mt792x_mcu_get_stat(struct mt792x_dev *dev,
+ struct mt7925_sta_stats *stats)
+{
+ u16 len = 0;
+ int ret = 0;
+ struct mt7925_sta_stats_event *event = NULL;
+ struct sk_buff *skb = NULL;
+ struct mt7925_sta_stats_req req = {
+ .tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_STA),
+ .len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),
+ .lls_read_clear = false,
+ .reset_counter = false,
+ };
+
+ ret = mt7925_get_ap_sta_rec_idx(dev, &req.sta_rec_idx);
+ if (ret)
+ return ret;
+
+ if (!stats)
+ return -EINVAL;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_STAT_INFO),
+ &req, sizeof(req), true, &skb);
+
+ if (ret)
+ return ret;
+
+ event = (struct mt7925_sta_stats_event *)skb->data;
+
+ if (le16_to_cpu(event->tag) != UNI_CMD_ID_STATISTICS_STA) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ len = le16_to_cpu(event->len);
+ if (len < sizeof(*event) - sizeof(event->rsv) ||
+ len > skb->len - sizeof(event->rsv) || !IS_ALIGNED(len, 4)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ if (event->stats.version != MT7925_STA_STATS_VERSION) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ if (!(le32_to_cpu(event->stats.flags) & MT7925_STA_STATS_VALID)) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ memcpy(stats, &event->stats, sizeof(*stats));
+
+out:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,
+ const u32 *counters, u8 counter_num,
+ u64 *values)
+{
+ u8 *req;
+ u8 *tlv, *tlv_end;
+ u16 req_len;
+ int i, ret;
+ struct mt7925_mib_hdr *req_hdr;
+ struct mt7925_mib_data *req_tlv;
+ struct sk_buff *skb;
+
+ if (!counters || !values || !counter_num ||
+ counter_num > MT7925_MIB_MAX_CNT)
+ return -EINVAL;
+
+ /* clear output; counters not returned by firmware stay 0 */
+ memset(values, 0, counter_num * sizeof(*values));
+
+ req_len = sizeof(struct mt7925_mib_hdr) +
+ counter_num * sizeof(struct mt7925_mib_data);
+
+ req = kzalloc(req_len, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req_hdr = (struct mt7925_mib_hdr *)req;
+ req_hdr->band_idx = band_idx;
+
+ req_tlv = (struct mt7925_mib_data *)(req + sizeof(*req_hdr));
+ for (i = 0; i < counter_num; i++) {
+ req_tlv[i].tag = cpu_to_le16(UNI_CMD_MIB_DATA);
+ req_tlv[i].len = cpu_to_le16(sizeof(struct mt7925_mib_data));
+ req_tlv[i].counter = cpu_to_le32(counters[i]);
+ }
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_MIB_INFO), req,
+ req_len, true, &skb);
+ kfree(req);
+ if (ret)
+ return ret;
+
+ if (skb->len < sizeof(struct mt7925_mib_hdr)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ /* walk the returned TLVs, match each counter ID to the request */
+ tlv = skb->data + sizeof(struct mt7925_mib_hdr);
+ tlv_end = skb->data + skb->len;
+
+ while (tlv + sizeof(struct mt7925_mib_data) <= tlv_end) {
+ struct mt7925_mib_data *evt_tlv =
+ (struct mt7925_mib_data *)tlv;
+ u16 tag = le16_to_cpu(evt_tlv->tag);
+ u16 len = le16_to_cpu(evt_tlv->len);
+ u32 counter;
+
+ if (len < sizeof(struct mt7925_mib_data) ||
+ tlv + len > tlv_end)
+ break;
+
+ if (tag == UNI_CMD_MIB_DATA) {
+ counter = le32_to_cpu(evt_tlv->counter);
+
+ if (counter < MT7925_MIB_CNT_MAX_NUM) {
+ for (i = 0; i < counter_num; i++) {
+ if (counters[i] == counter) {
+ values[i] =
+ le64_to_cpu(evt_tlv->data);
+ break;
+ }
+ }
+ }
+ }
+
+ tlv += len;
+ }
+
+ ret = 0;
+
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx)
+{
+ char * const ofdm_str[] = {
+ "6M", "9M", "12M", "18M", "24M", "36M", "48M", "54M", "N/A"
+ };
+
+ switch (ofdm_idx) {
+ case 11: return ofdm_str[0]; /* 6M */
+ case 15: return ofdm_str[1]; /* 9M */
+ case 10: return ofdm_str[2]; /* 12M */
+ case 14: return ofdm_str[3]; /* 18M */
+ case 9: return ofdm_str[4]; /* 24M */
+ case 13: return ofdm_str[5]; /* 36M */
+ case 8: return ofdm_str[6]; /* 48M */
+ case 12: return ofdm_str[7]; /* 54M */
+ default: return ofdm_str[8];
+ }
+}
+
+/* mt792x_mcu_get_wtbl_rate - fetch the firmware auto-rate table for a WCID
+ * @dev: device
+ * @wlan_idx: HW WTBL / WCID index (see mt7925_sta_stats.wtbl_idx)
+ * @rate: out, filled with the auto-rate table snapshot
+ *
+ * Mirror of Gen4m wlanoidGetStatWtbl(): send UNI_CMD_GET_STAT_INFO with the
+ * WTBL rate TLV (cmd tag 10) and parse the reply (event tag 12) into @rate.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,
+ struct mt7925_wtbl_rate *rate)
+{
+ int ret;
+ struct mt7925_wtbl_rate_event *event = NULL;
+ struct sk_buff *skb = NULL;
+ struct mt7925_wtbl_rate_req req = {
+ .tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_WTBL),
+ .len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),
+ .wlan_idx = cpu_to_le16(wlan_idx),
+ };
+
+ if (!rate)
+ return -EINVAL;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_STAT_INFO),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ if (skb->len < sizeof(*event)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ event = (struct mt7925_wtbl_rate_event *)skb->data;
+
+ if (le16_to_cpu(event->rate.tag) != MT7925_UNI_EVENT_STATISTICS_WTBL) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ memcpy(rate, &event->rate, sizeof(*rate));
+ ret = 0;
+
+out:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+/**
+ * mt7925_mcu_get_link_quality - query RSSI and TX link speed for a band
+ * @dev: device
+ * @band_idx: band/BSS index (0..3)
+ * @rssi: out, moving-average beacon RSSI in dBm (may be NULL)
+ * @tx_link_speed_kbps: out, TX rate in kbit/s (may be NULL)
+ *
+ * Return: 0 on success, -ENOENT if the band's link quality is not ready.
+ *
+ * Only RSSI and TX rate come from firmware here; for RX rate read wcid->rate.
+ */
+int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,
+ s8 *rssi, u32 *tx_link_speed_kbps)
+{
+ int ret;
+ struct mt7925_lq_event *event;
+ struct mt7925_link_quality *lq;
+ struct sk_buff *skb;
+ struct mt7925_lq_req req = {
+ .tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_LINK_QUALITY),
+ .len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),
+ };
+
+ if (band_idx >= MT7925_LQ_BAND_NUM)
+ return -EINVAL;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_STAT_INFO), &req,
+ sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ if (skb->len < sizeof(*event)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ event = (struct mt7925_lq_event *)skb->data;
+
+ if (le16_to_cpu(event->tag) != UNI_CMD_ID_STATISTICS_LINK_QUALITY) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ lq = &event->lq[band_idx];
+ if (!lq->is_ready) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (rssi)
+ *rssi = lq->rssi;
+
+ /* firmware reports TX rate in 500 Kb/s units -> kbit/s */
+ if (tx_link_speed_kbps)
+ *tx_link_speed_kbps = le16_to_cpu(lq->link_speed) * 500;
+
+ ret = 0;
+
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/stats.h b/drivers/net/wireless/mediatek/mt76/mt7925/stats.h
new file mode 100644
index 0000000000000..a70b9eb3aa806
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/stats.h
@@ -0,0 +1,309 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/* Copyright (C) 2026 MediaTek Inc. */
+
+#ifndef __MT7925_STATS_H
+#define __MT7925_STATS_H
+
+#include <linux/if_ether.h>
+#include <linux/types.h>
+#include "../mt76_connac_mcu.h"
+
+#define MT7925_STA_STATS_AC_NUM 4
+#define MT7925_STA_STATS_BAND_NUM 2
+#define MT7925_STA_STATS_AGG_RANGE_NUM 16
+#define MT7925_STA_STATS_TX_QUALITY_NUM 4
+#define MT7925_TX_MODE_NUM 16
+#define MT7925_TX_RATE_CCK_NUM 5
+#define MT7925_TX_RATE_BW_NUM 6
+
+/* HW rate code (16-bit) field extract, mirror Gen4m CONNAC3X_HW_TX_RATE_TO_*.
+ * The auto-rate table stores one rate code per entry.
+ */
+#define MT7925_HW_RATE_TO_MCS(_x) (((_x) & GENMASK(5, 0)) >> 0)
+#define MT7925_HW_RATE_TO_MODE(_x) (((_x) & GENMASK(9, 6)) >> 6)
+#define MT7925_HW_RATE_TO_NSS(_x) (((_x) & GENMASK(13, 10)) >> 10)
+#define MT7925_HW_RATE_TO_STBC(_x) (((_x) & BIT(14)) >> 14)
+#define MT7925_HW_RATE_TO_DCM(_x) (((_x) & BIT(4)) >> 4)
+#define MT7925_HW_RATE_TO_106T(_x) (((_x) & BIT(5)) >> 5)
+#define MT7925_HW_RATE_UNMASK_DCM(_r) ((u8)(_r) & 0xef)
+#define MT7925_HW_RATE_UNMASK_106T(_r) ((u8)(_r) & 0xdf)
+
+/* Number of entries in the firmware auto-rate table (mirror Gen4m
+ * AUTO_RATE_NUM). RA cycles through these and reports which one is in use
+ * via wtbl->rate_idx.
+ */
+#define MT7925_AUTO_RATE_NUM 8
+
+/* Firmware EVENT_STATISTICS sub-event tags. The WTBL rate request uses cmd tag
+ * UNI_CMD_ID_STATISTICS_WTBL (10) but the firmware replies with event tag 12.
+ */
+#define MT7925_UNI_EVENT_STATISTICS_WTBL 12
+
+/* CONNAC3X TX Vector BBP latch bit fields (mirror cmm_asic_connac3x.h).
+ * These operate on the 3-DWORD tx_vector[band].txv[3] array.
+ */
+#define MT7925_TXV_GET_TX_RATE(_txv) ((_txv)[2] & 0x7f)
+#define MT7925_TXV_GET_TX_LDPC(_txv) (((_txv)[2] & (0x1 << 7)) >> 7)
+#define MT7925_TXV_GET_TX_STBC(_txv) (((_txv)[0] & (0x3 << 6)) >> 6)
+#define MT7925_TXV_GET_TX_FRMODE(_txv) (((_txv)[0] & (0x7 << 8)) >> 8)
+#define MT7925_TXV_GET_TX_MODE(_txv) (((_txv)[0] & (0xf << 12)) >> 12)
+#define MT7925_TXV_GET_TX_NSTS(_txv) (((_txv)[2] & (0xfU << 28)) >> 28)
+#define MT7925_TXV_GET_TX_PWR(_txv) (((_txv)[0] & (0xff << 16)) >> 16)
+#define MT7925_TXV_GET_TX_SGI(_txv) (((_txv)[1] & (0x3 << 26)) >> 26)
+#define MT7925_TXV_GET_TX_SPE_IDX(_txv) (((_txv)[0] & (0x1f << 0)) >> 0)
+#define MT7925_TXV_GET_TX_DCM(_txv) (((_txv)[2] & (0x1 << 4)) >> 4)
+#define MT7925_TXV_GET_TX_106T(_txv) (((_txv)[2] & (0x1 << 5)) >> 5)
+#define MT7925_TXV_RATE_UNMASK_DCM(_r) ((u8)(_r) & 0xef)
+#define MT7925_TXV_RATE_UNMASK_106T(_r) ((u8)(_r) & 0xdf)
+
+extern const char * const mt7925_tx_mode_str[MT7925_TX_MODE_NUM];
+extern const char * const mt7925_tx_rate_cck_str[MT7925_TX_RATE_CCK_NUM];
+extern const char * const mt7925_tx_rate_bw_str[MT7925_TX_RATE_BW_NUM];
+
+/* TX rate mode, mirror Gen4m TX_RATE_MODE_* (see nic_rate.h). Used to decode
+ * both the TX Vector BBP latch and the firmware auto-rate table rate codes.
+ */
+enum mt7925_tx_rate_mode {
+ MT7925_TX_RATE_MODE_CCK = 0,
+ MT7925_TX_RATE_MODE_OFDM = 1,
+ MT7925_TX_RATE_MODE_HTMIX = 2,
+ MT7925_TX_RATE_MODE_HTGF = 3,
+ MT7925_TX_RATE_MODE_VHT = 4,
+ MT7925_TX_RATE_MODE_PLR = 5,
+ MT7925_TX_RATE_MODE_HE_SU = 8,
+ MT7925_TX_RATE_MODE_HE_ER = 9,
+ MT7925_TX_RATE_MODE_HE_TRIG = 10,
+ MT7925_TX_RATE_MODE_HE_MU = 11,
+ MT7925_TX_RATE_MODE_EHT_ER = 13,
+ MT7925_TX_RATE_MODE_EHT_TRIG = 14,
+ MT7925_TX_RATE_MODE_EHT_MU = 15,
+};
+
+enum {
+ UNI_CMD_MIB_DATA,
+};
+
+enum stats_query_mib_array_index {
+ QUERY_MIB_CNT_RX_FCS_ERR = 0,
+ QUERY_MIB_CNT_RX_FIFO_OVERFLOW,
+ QUERY_MIB_CNT_RX_MPDU,
+ QUERY_MIB_CNT_AMPDU_RX_COUNT,
+ QUERY_MIB_CNT_PF_DROP,
+ QUERY_MIB_CNT_LEN_MISMATCH,
+ QUERY_MIB_CNT_CHANNEL_IDLE,
+ QUERY_MIB_CNT_CCA_NAV_TX_TIME,
+ QUERY_MIB_CNT_MDRDY,
+ QUERY_MIB_CNT_RX_CCK_MDRDY_TIME,
+ QUERY_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME,
+ QUERY_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME,
+ QUERY_MIB_CNT_P_CCA_TIME,
+ QUERY_MIB_CNT_S_CCA_TIME,
+ QUERY_MIB_CNT_P_ED_TIME,
+ QUERY_MIB_CNT_BCN_TX,
+ QUERY_MIB_CNT_TX_BW_40MHZ,
+ QUERY_MIB_CNT_TX_BW_80MHZ,
+ QUERY_MIB_CNT_TX_BW_160MHZ,
+ QUERY_MIB_CNT_BSS0_BA_MISS,
+ QUERY_MIB_CNT_BSS0_RTS_TX_CNT,
+ QUERY_MIB_CNT_BSS0_FRAME_RETRY,
+ QUERY_MIB_CNT_BSS0_FRAME_RETRY_2,
+ QUERY_MIB_CNT_BSS0_RTS_RETRY,
+ QUERY_MIB_CNT_BSS0_ACK_FAIL,
+ QUERY_MIB_CNT_AMPDU,
+ QUERY_MIB_CNT_AMPDU_MPDU,
+ QUERY_MIB_CNT_AMPDU_ACKED,
+ QUERY_MIB_CNT_MAX_NUM,
+};
+
+enum stats_trx_agg_range {
+ STAT_MIB_CNT_TRX_AGG_RANGE0_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE1_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE2_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE3_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE4_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE5_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE6_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE7_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE_MAX_NUM
+};
+
+enum {
+ MT7925_BW_20 = 0,
+ MT7925_BW_40,
+ MT7925_BW_80,
+ MT7925_BW_160,
+};
+
+struct mt7925_sta_stats_ac {
+ __le32 tx_fail;
+ __le32 tx_retry;
+} __packed;
+
+struct mt7925_sta_stats_tx_vector {
+ __le32 txv[3];
+} __packed;
+
+struct mt7925_sta_stats_mib {
+ __le32 rx_mpdu_cnt;
+ __le32 fcs_error;
+ __le32 rx_fifo_full;
+ __le32 ampdu_tx_sf_cnt;
+ __le32 ampdu_tx_ack_sf_cnt;
+ __le32 tx_range_ampdu_cnt[MT7925_STA_STATS_AGG_RANGE_NUM];
+} __packed;
+
+/* Firmware EVENT_STA_STATISTICS body. */
+struct mt7925_sta_stats {
+ u8 version;
+ u8 rsv[3];
+ __le32 flags;
+
+ u8 sta_idx;
+ u8 bss_idx;
+ u8 wtbl_idx;
+ u8 rsv1;
+
+ u8 mac_addr[ETH_ALEN];
+ u8 per;
+ u8 rcpi;
+
+ __le32 phy_mode;
+ __le16 link_speed; /* 0.5 Mbit/s units */
+ u8 link_quality;
+ u8 link_reserved;
+
+ __le32 tx_count;
+ __le32 tx_fail_count;
+ __le32 tx_life_timeout_count;
+ __le32 tx_done_air_time;
+ __le32 transmit_count;
+ __le32 transmit_fail_count;
+
+ struct mt7925_sta_stats_ac ac[MT7925_STA_STATS_AC_NUM];
+
+ u8 temperature;
+ u8 skip_ar;
+ u8 ar_table_idx;
+ u8 rate_entry_idx;
+ u8 rate_entry_idx_prev;
+ u8 tx_sgi_detect_pass_cnt;
+ u8 ave_per;
+ u8 rsv2;
+
+ __le32 agg_range_ctrl[2];
+ u8 range_mode;
+ u8 rsv3[3];
+ __le32 agg_range_ctrl_ext[6];
+
+ u8 ar_state_curr;
+ u8 ar_state_prev;
+ u8 ar_action_type;
+ u8 highest_rate_cnt;
+ u8 lowest_rate_cnt;
+ u8 rsv4;
+ __le16 train_up;
+ __le16 train_down;
+ u8 rsv5[2];
+ __le32 rate1_tx_cnt;
+ __le32 rate1_fail_cnt;
+
+ struct mt7925_sta_stats_tx_vector tx_vector[MT7925_STA_STATS_BAND_NUM];
+ struct mt7925_sta_stats_mib mib[MT7925_STA_STATS_BAND_NUM];
+
+ u8 is_force_tx_stream;
+ u8 is_force_se_off;
+ __le16 ra_running_cnt;
+ u8 ra_status;
+ u8 max_ampdu_factor;
+ u8 tx_quality[MT7925_STA_STATS_TX_QUALITY_NUM];
+ u8 tx_rate_up_penalty;
+ u8 low_traffic_mode;
+ u8 low_traffic_count;
+ u8 low_traffic_dashboard;
+ u8 dynamic_sgi_state;
+ u8 dynamic_sgi_score;
+ u8 dynamic_bw_state;
+ u8 dynamic_gband_256qam_state;
+ u8 vht_non_sp_rate_state;
+ u8 rsv6[3];
+ u8 rsv7[2];
+} __packed;
+
+struct mt7925_sta_rec_lookup {
+ int sta_rec_idx;
+};
+
+/* Firmware auto-rate table snapshot, mirror Gen4m struct UNI_EVENT_STAT_WTBL.
+ *
+ * The firmware RA maintains up to MT7925_AUTO_RATE_NUM candidate rates in
+ * rate_code[]. rate_idx tells which entry is currently in use, so a dump can
+ * point at it with "-->". fcap is the bandwidth capability and the ldpc/sgi
+ * flags describe the per-mode coding/guard-interval used for those rates.
+ */
+struct mt7925_wtbl_rate {
+ __le16 tag;
+ __le16 len;
+ u8 rx_rcpi0;
+ u8 rx_rcpi1;
+ u8 cbrn;
+ u8 fcap;
+ u8 spe_idx;
+ u8 g2; /* SGI enabled, non-HE, BW20 */
+ u8 g4; /* SGI enabled, non-HE, BW40 */
+ u8 g8; /* SGI enabled, non-HE, BW80 */
+ u8 g16; /* SGI enabled, non-HE, BW160 */
+ u8 g2_he; /* GI, HE, BW20 */
+ u8 g4_he; /* GI, HE, BW40 */
+ u8 g8_he; /* GI, HE, BW80 */
+ u8 g16_he; /* GI, HE, BW160 */
+ u8 gi_eht; /* GI, EHT */
+ u8 ht_ldpc;
+ u8 vht_ldpc;
+ u8 he_ldpc;
+ u8 eht_ldpc;
+ u8 af;
+ u8 rate_idx; /* index into rate_code[] currently in use */
+ __le16 rate_code[MT7925_AUTO_RATE_NUM];
+ __le32 rsv[4];
+} __packed;
+
+int
+mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx);
+
+void
+mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3]);
+
+u8
+mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap);
+
+u8
+mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode);
+
+char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx);
+
+int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,
+ struct mt7925_wtbl_rate *rate);
+
+int mt792x_mcu_get_stat(struct mt792x_dev *dev,
+ struct mt7925_sta_stats *stats);
+
+int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,
+ const u32 *counters, u8 counter_num,
+ u64 *values);
+
+/* GET_STAT_INFO (UNI_CMD_ID_GET_STATISTICS = 0x23),
+ * sub-command UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1.
+ *
+ * @band_idx: band/BSS index (0..3)
+ * @rssi: out, moving-average beacon RSSI (dBm), may be NULL
+ * @tx_link_speed_kbps: out, TX link speed in kbit/s, may be NULL
+ *
+ * Returns 0 on success, -ENOENT if the band's link quality is not ready.
+ *
+ * NOTE: firmware provides only RSSI and TX rate here. RX rate/bandwidth are
+ * not in this event; read wcid->rate for the RX rate.
+ */
+int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,
+ s8 *rssi, u32 *tx_link_speed_kbps);
+
+#endif
|
| 3/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 26247 output: 45 thoughts: 675 Thoughts: **Analyzing this Patch for Fuzzing Potential** Okay, let's break this down. The patch touches files related to the MediaTek MT7925 Wi-Fi driver within the `mt76` framework. Specifically, I see changes to the MCU header, Makefile, debugfs, and statistics code for the MT7925. My initial thought is to determine if this is a good candidate for fuzzing. First, I need to understand the hardware. The MT7925 is a MediaTek chipset, so it needs actual hardware, right? PCIe or USB? Based on the file paths, my assumption is that it's probably PCIe, but let's not jump to conclusions. Now, let's consider the fuzzing guidance. I know I should disregard changes that are documentation, comments, decorative logging, simple constant changes, unreachable code in virtualized environments, vendor-specific drivers requiring dedicated hardware, or cleanup callbacks. So, I need to determine if this patch falls into any of those categories. Hmm, can MT7925 even be emulated, or reach USB gadget? Wait, I seem to recall that the MT7925 driver has both PCIe (`CONFIG_MT7925E`) and USB (`CONFIG_MT7925U`) variants. So, maybe a USB device can be emulated using USB gadget, like raw-gadget, or dummy_hcd? Since MT7925 is a vendor-specific Wi-Fi driver, similar to ath9k_htc, mt7601u, and rtl8xxxu, I should investigate if it's already tested or fuzzed in syzkaller. Let's dig deeper: Does the MT7925 require firmware loading on probe? Can USB raw-gadget or USB emulation actually simulate an MT7925U device? Does the USB-fuzzer bind to the MT7925U? I should also check the USB ID table. Okay, time to do some kernel grepping to understand the relationship between MT7925, MT7925U, and the broader MT76 framework. That should give me a better idea of the hardware requirements and fuzzing possibilities. |
| 4/2 | 2026/08/31 03:56 | tool | grepper |
0mArgs:{
"Expression": "MODULE_DEVICE_TABLE.*usb",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c=303=static int mt7925u_resume(struct usb_interface *intf)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-350-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:351:MODULE_DEVICE_TABLE(usb, mt7925u_device_table);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-352-MODULE_FIRMWARE(MT7925_FIRMWARE_WM);\n"
} |
| 5/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 27625 output: 48 thoughts: 241 Thoughts: **Analyzing the MT7925U Probe and Debugfs Implementation** Okay, so I'm diving into the recent changes, specifically focusing on what happens during the `mt7925u` probe. It looks like this patch introduces a "stats" debugfs file. Ah, yes, I see it's created using `debugfs_create_devm_seqfile` within `mt7925_init_debugfs`. Essentially, the patch provides visibility into internal statistics through that debugfs interface. Now, let's break down the functions involved in generating those stats. There's `mt792x_stats` which, I assume, handles the overall stats output. Then, we have a series of helpers to collect and present various pieces of information: `mt7925_mcu_get_mib_info`, `mt7925_print_last_tx_rate`, `mt7925_wtbl_get_sgi`, `mt7925_wtbl_get_ldpc`, `mt792x_mcu_get_stat`, `mt792x_mcu_get_wtbl_rate`, `mt7925_mcu_get_link_quality`, and `mt7925_get_ap_sta_rec_idx`. These seem to be involved in pulling specific data points related to the MCU, wireless table, TX rates, and link quality. Hold on... where is `mt7925_init_debugfs` actually called? I need to track down the entry point for this debugfs setup to understand the context and timing of when these stats become available. Time to trace the function calls. |
| 6/2 | 2026/08/31 03:56 | tool | grepper |
0mArgs:{
"Expression": "mt7925_init_debugfs",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c=416=static int mt792x_stats(struct seq_file *s, void *data)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-651-\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:652:int mt7925_init_debugfs(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-653-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c=190=static void mt7925_init_work(struct work_struct *work)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-218-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:219:\tret = mt7925_init_debugfs(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-220-\tif (ret) {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=321=int mt7925_init_mlo_caps(struct mt792x_phy *phy);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:322:int mt7925_init_debugfs(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-323-\n"
} |
| 7/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 28766 output: 50 thoughts: 62 Thoughts: **Diving into the MT7925 Initialization** Okay, so I need to understand the initialization process for the MT7925 wireless chip, specifically focusing on the `mt7925_init_work` function. Right, so that's located in the `drivers/net/wireless/mediatek/mt76/mt7925/init.c` file. Let's get the file open...and zoom in on lines 190 to, say, 230. That should give me a good chunk of the relevant code to analyze. I'm expecting to see the core setup routines, resource allocation, and any initial hardware configuration being performed there. Let's see what Mediatek is up to. |
| 8/2 | 2026/08/31 03:56 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/init.c",
"FirstLine": 180,
"LineCount": 60
}Results: {
"Contents": " 180:\t\n 181:\t\tsband = wiphy-\u003ebands[NL80211_BAND_2GHZ];\n 182:\t\the_cap = sband ? ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_NAN)\n 183:\t\t\t : NULL;\n 184:\t\tif (he_cap)\n 185:\t\t\twiphy-\u003enan_capa.phy.he = *he_cap;\n 186:\t\n 187:\t\treturn 0;\n 188:\t}\n 189:\t\n 190:\tstatic void mt7925_init_work(struct work_struct *work)\n 191:\t{\n 192:\t\tstruct mt792x_dev *dev = container_of(work, struct mt792x_dev,\n 193:\t\t\t\t\t\t init_work);\n 194:\t\tint ret;\n 195:\t\n 196:\t\tret = mt7925_init_hardware(dev);\n 197:\t\tif (ret)\n 198:\t\t\treturn;\n 199:\t\n 200:\t\tmt76_set_stream_caps(\u0026dev-\u003emphy, true);\n 201:\t\tmt7925_set_stream_he_eht_caps(\u0026dev-\u003ephy);\n 202:\t\tmt792x_config_mac_addr_list(dev);\n 203:\t\n 204:\t\tret = mt7925_init_mlo_caps(\u0026dev-\u003ephy);\n 205:\t\tif (ret) {\n 206:\t\t\tdev_err(dev-\u003emt76.dev, \"MLO init failed\\n\");\n 207:\t\t\treturn;\n 208:\t\t}\n 209:\t\n 210:\t\tdev-\u003emt76.init_wiphy = mt7925_init_nan_cap;\n 211:\t\n 212:\t\tret = mt76_register_device(\u0026dev-\u003emt76, true, mt76_rates,\n 213:\t\t\t\t\t ARRAY_SIZE(mt76_rates));\n 214:\t\tif (ret) {\n 215:\t\t\tdev_err(dev-\u003emt76.dev, \"register device failed\\n\");\n 216:\t\t\treturn;\n 217:\t\t}\n 218:\t\n 219:\t\tret = mt7925_init_debugfs(dev);\n 220:\t\tif (ret) {\n 221:\t\t\tdev_err(dev-\u003emt76.dev, \"register debugfs failed\\n\");\n 222:\t\t\treturn;\n 223:\t\t}\n 224:\t\n 225:\t\tret = mt7925_thermal_init(\u0026dev-\u003ephy);\n 226:\t\tif (ret) {\n 227:\t\t\tdev_err(dev-\u003emt76.dev, \"thermal init failed\\n\");\n 228:\t\t\treturn;\n 229:\t\t}\n 230:\t\n 231:\t\tret = mt7925_mcu_set_thermal_protect(dev);\n 232:\t\tif (ret) {\n 233:\t\t\tdev_err(dev-\u003emt76.dev, \"thermal protection enable failed\\n\");\n 234:\t\t\treturn;\n 235:\t\t}\n 236:\t\n 237:\t\t/* we support chip reset now */\n 238:\t\tdev-\u003ehw_init_done = true;\n 239:\t\n"
} |
| 9/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 29974 output: 47 thoughts: 20 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into the Hardware Initialization** Alright, let's dissect this `mt7925_init_hardware(dev)` function. The name itself is pretty explicit – we're looking at the core hardware initialization routine for the MT7925 device, `dev`. Given what I know about MediaTek's architecture, I'm expecting this to be the point where we bring the radio up from a power-on reset state, configure clocks and power domains, and potentially initialize any essential internal SRAM or register banks. I'll need to keep an eye out for how this function interacts with the PCI/USB bus. I bet there is some sequence of register writes involved in telling the chip how to manage its interrupts and DMA. I'll need to confirm what steps it is taking so that it is able to properly configure the driver's transmit and receive queues. There may be some calibration steps in here, maybe load firmware or microcode. I anticipate some bus transaction to load firmware if this function is responsible for initial code loading. I'm keen to see if this handles any security-related hardware initialization, like key setup or secure boot sequence. I know the MT7925 is reasonably modern, and I suspect there are some fairly complex hardware dependencies that are going to need addressing. Let's dig in and see exactly how they're handling that. |
| 10/2 | 2026/08/31 03:56 | tool | grepper |
0mArgs:{
"Expression": "mt7925_init_hardware",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/init.c=98=EXPORT_SYMBOL_GPL(mt7925_mac_init);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-99-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:100:static int __mt7925_init_hardware(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-101-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-132-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:133:static int mt7925_init_hardware(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-134-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-144-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:145:\t\tret = __mt7925_init_hardware(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-146-\t\tif (!ret)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c=190=static void mt7925_init_work(struct work_struct *work)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-195-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:196:\tret = mt7925_init_hardware(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-197-\tif (ret)\n"
} |
| 11/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 30878 output: 50 thoughts: 16 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Diving into `__mt7925_init_hardware`** Okay, time to dig into the `__mt7925_init_hardware` function. I need to refresh my memory on what exactly this is doing. My guess is it's the crucial initialization routine for the MT7925 Wi-Fi chip, likely dealing with hardware bring-up. I'm immediately looking for things like: register access, clock configuration, PHY initialization sequences, maybe DMA setup if this architecture leverages it... the usual suspects when you're bootstrapping a complex piece of silicon. I want to understand the *order* of operations, that's often critical in these initialization routines. Any unusual hardware quirks or workarounds for errata I need to be aware of? This is where the real "magic" happens, or conversely, where bugs like to hide. Let's see if the code is well-commented, especially around the register writes. I'll be looking for any hints about potential power-saving features that are being enabled from the start. Gotta check the return values, too. Any error handling? What does it do on failure? This is fundamental, so I need to be sure I'm following every step. |
| 12/2 | 2026/08/31 03:56 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/init.c",
"FirstLine": 100,
"LineCount": 40
}Results: {
"Contents": " 100:\tstatic int __mt7925_init_hardware(struct mt792x_dev *dev)\n 101:\t{\n 102:\t\tint ret;\n 103:\t\n 104:\t\tret = mt792x_mcu_init(dev);\n 105:\t\tif (ret)\n 106:\t\t\tgoto out;\n 107:\t\n 108:\t\tret = mt76_eeprom_override(\u0026dev-\u003emphy);\n 109:\t\tif (ret)\n 110:\t\t\tgoto out;\n 111:\t\n 112:\t\tret = mt7925_mcu_set_eeprom(dev);\n 113:\t\tif (ret)\n 114:\t\t\tgoto out;\n 115:\t\n 116:\t\tret = mt7925_mac_init(dev);\n 117:\t\tif (ret)\n 118:\t\t\tgoto out;\n 119:\t\n 120:\t\tif (is_mt7927(\u0026dev-\u003emt76)) {\n 121:\t\t\tret = mt7925_mcu_set_dbdc(\u0026dev-\u003emphy, true);\n 122:\t\t\tif (ret) {\n 123:\t\t\t\tdev_warn(dev-\u003emt76.dev,\n 124:\t\t\t\t\t \"MT7927 DBDC enable failed: %d\\n\", ret);\n 125:\t\t\t\tret = 0;\n 126:\t\t\t}\n 127:\t\t}\n 128:\t\n 129:\tout:\n 130:\t\treturn ret;\n 131:\t}\n 132:\t\n 133:\tstatic int mt7925_init_hardware(struct mt792x_dev *dev)\n 134:\t{\n 135:\t\tint ret, i;\n 136:\t\n 137:\t\tset_bit(MT76_STATE_INITIALIZED, \u0026dev-\u003emphy.state);\n 138:\t\n 139:\t\tfor (i = 0; i \u003c MT792x_MCU_INIT_RETRY_COUNT; i++) {\n"
} |
| 13/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 31798 output: 46 thoughts: 468 Thoughts: **My Assessment of the Fuzzing Potential** Okay, so I need to figure out if these vendor Wi-Fi drivers, specifically mt76 and mt7925, are worth fuzzing. The initial thought was to check if they *need* physical hardware beyond what QEMU can emulate, or if USB Wi-Fi drivers are even fuzzable. But let's rewind and meticulously re-examine the criteria for what isn't worth fuzzing. I need to make sure I don't overlook any subtleties. It's easy to get lost in the weeds. Right, so the criteria seem to steer me away from changes related to documentation, Kconfig, comments, cosmetic logging, non-functional constant modifications, unreachable code paths in emulated environments (even with software emulated hardware), specific vendor PCIe hardware, and teardown callbacks. This gives a clearer picture of what I am looking for. Now, hold on. Can USB devices be emulated well enough via USB Raw Gadget or `dummy_hcd` in QEMU, or even in a framework like Syzkaller? The answer, as I recall, is a resounding yes! USB Raw Gadget is powerful and can emulate *any* USB device, by giving it USB descriptors to match vendor and product IDs. I think it may be key. But, a critical question arises: Can `mt7925` *successfully probe* through the USB raw gadget to the point where debugfs entries are created and interacted with? And can the USB Raw Gadget allow me to fuzz the USB driver probes and MCU communications? I need to be sure. Aha! In Syzkaller, USB fuzzing using `syz_usb_connect` and the raw gadget functionality is *actively* employed to fuzz USB drivers! That is the core of it. When Syzkaller fuzzes USB drivers, it connects USB devices, and provides necessary responses to control, bulk, and interrupt transfers. So it works. Now I am going to see what `mt7925u_probe` actually does. |
| 14/2 | 2026/08/31 03:56 | tool | grepper |
0mArgs:{
"Expression": "mt7925u_probe",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c=80=static int mt7925u_mac_reset(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-149-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:150:static int mt7925u_probe(struct usb_interface *usb_intf,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-151-\t\t\t const struct usb_device_id *id)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=355=static struct usb_driver mt7925u_driver = {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-357-\t.id_table\t= mt7925u_device_table,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:358:\t.probe\t\t= mt7925u_probe,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-359-\t.disconnect\t= mt792xu_disconnect,\n"
} |
| 15/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 33104 output: 50 thoughts: 39 Thoughts: Here's my summary, as if I were thinking these thoughts: **Diving into the MT7925U USB Probe Function** Okay, time to get my hands dirty. Let's dig into the `mt7925u_probe` function. I'm heading over to the `drivers/net/wireless/mediatek/mt76/mt7925/usb.c` file. This is the entry point for initializing the MT7925U wireless device over USB, so understanding this is crucial for the overall USB bring-up process. I'm interested in how it handles device enumeration, resource allocation, initialization of the driver's internal data structures, and the setup of the USB endpoints. Let's see what Mediatek's implementation has cooked up here... I'm particularly interested in how they're handling power management within the probe too. I want to see if they're doing anything clever, or using the standard framework to make this work. |
| 16/2 | 2026/08/31 03:56 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c",
"FirstLine": 150,
"LineCount": 80
}Results: {
"Contents": " 150:\tstatic int mt7925u_probe(struct usb_interface *usb_intf,\n 151:\t\t\t\t const struct usb_device_id *id)\n 152:\t{\n 153:\t\tstatic const struct mt76_driver_ops drv_ops = {\n 154:\t\t\t.txwi_size = MT_SDIO_TXD_SIZE,\n 155:\t\t\t.drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ |\n 156:\t\t\t\t MT_DRV_AMSDU_OFFLOAD,\n 157:\t\t\t.survey_flags = SURVEY_INFO_TIME_TX |\n 158:\t\t\t\t\tSURVEY_INFO_TIME_RX |\n 159:\t\t\t\t\tSURVEY_INFO_TIME_BSS_RX,\n 160:\t\t\t.tx_prepare_skb = mt7925_usb_sdio_tx_prepare_skb,\n 161:\t\t\t.tx_complete_skb = mt7925_usb_sdio_tx_complete_skb,\n 162:\t\t\t.tx_status_data = mt7925_usb_sdio_tx_status_data,\n 163:\t\t\t.rx_skb = mt7925_queue_rx_skb,\n 164:\t\t\t.rx_check = mt7925_rx_check,\n 165:\t\t\t.sta_add = mt7925_mac_sta_add,\n 166:\t\t\t.sta_event = mt7925_mac_sta_event,\n 167:\t\t\t.sta_remove = mt7925_mac_sta_remove,\n 168:\t\t\t.update_survey = mt792x_update_channel,\n 169:\t\t};\n 170:\t\tstatic const struct mt792x_hif_ops hif_ops = {\n 171:\t\t\t.mcu_init = mt7925u_mcu_init,\n 172:\t\t\t.init_reset = mt792xu_init_reset,\n 173:\t\t\t.reset = mt7925u_mac_reset,\n 174:\t\t};\n 175:\t\tstatic struct mt76_bus_ops bus_ops = {\n 176:\t\t\t.rr = mt792xu_rr,\n 177:\t\t\t.wr = mt792xu_wr,\n 178:\t\t\t.rmw = mt792xu_rmw,\n 179:\t\t\t.read_copy = mt76u_read_copy,\n 180:\t\t\t.write_copy = mt792xu_copy,\n 181:\t\t\t.type = MT76_BUS_USB,\n 182:\t\t};\n 183:\t\tstruct usb_device *udev = interface_to_usbdev(usb_intf);\n 184:\t\tstruct ieee80211_ops *ops;\n 185:\t\tstruct ieee80211_hw *hw;\n 186:\t\tstruct mt792x_dev *dev;\n 187:\t\tstruct mt76_dev *mdev;\n 188:\t\tu8 features;\n 189:\t\tint ret;\n 190:\t\n 191:\t\tops = mt792x_get_mac80211_ops(\u0026usb_intf-\u003edev, \u0026mt7925_ops,\n 192:\t\t\t\t\t (void *)id-\u003edriver_info, \u0026features);\n 193:\t\tif (!ops)\n 194:\t\t\treturn -ENOMEM;\n 195:\t\n 196:\t\tops-\u003estop = mt792xu_stop;\n 197:\t\n 198:\t\tmdev = mt76_alloc_device(\u0026usb_intf-\u003edev, sizeof(*dev), ops, \u0026drv_ops);\n 199:\t\tif (!mdev)\n 200:\t\t\treturn -ENOMEM;\n 201:\t\n 202:\t\tdev = container_of(mdev, struct mt792x_dev, mt76);\n 203:\t\tdev-\u003efw_features = features;\n 204:\t\tdev-\u003ehif_ops = \u0026hif_ops;\n 205:\t\tmt792xu_reset_work_init(dev);\n 206:\t\n 207:\t\tusb_reset_device(udev);\n 208:\t\n 209:\t\tusb_set_intfdata(usb_intf, dev);\n 210:\t\n 211:\t\tret = __mt76u_init(mdev, usb_intf, \u0026bus_ops);\n 212:\t\tif (ret \u003c 0)\n 213:\t\t\tgoto error;\n 214:\t\n 215:\t\tmdev-\u003erev = (mt76_rr(dev, MT_HW_CHIPID) \u003c\u003c 16) |\n 216:\t\t\t (mt76_rr(dev, MT_HW_REV) \u0026 0xff);\n 217:\t\tdev_dbg(mdev-\u003edev, \"ASIC revision: %04x\\n\", mdev-\u003erev);\n 218:\t\n 219:\t\tif (mt76_chip(mdev) == 0x6639) {\n 220:\t\t\tdev_dbg(mdev-\u003edev,\n 221:\t\t\t\t\"MT7927 raw CHIPID=0x%04x, forcing chip=0x7927\\n\",\n 222:\t\t\t\tmt76_chip(mdev));\n 223:\t\t\tmdev-\u003erev = (0x7927 \u003c\u003c 16) | (mdev-\u003erev \u0026 0xff);\n 224:\t\t}\n 225:\t\n 226:\t\tif (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {\n 227:\t\t\tret = mt792xu_wfsys_reset(dev);\n 228:\t\t\tif (ret)\n 229:\t\t\t\tgoto error;\n"
} |
| 17/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 34979 output: 50 thoughts: 18 Thoughts: Okay, let's dive into this `mt7925u_probe` function and see what's going on. I'm ready to dissect this piece of code. I want to understand exactly what the next steps are, the logical flow, and if there are any potential pitfalls. It's time to put my expertise to work and analyze this thoroughly. Let's get to it! |
| 18/2 | 2026/08/31 03:56 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c",
"FirstLine": 230,
"LineCount": 40
}Results: {
"Contents": " 230:\t\t}\n 231:\t\n 232:\t\tret = mt792xu_mcu_power_on(dev);\n 233:\t\tif (ret)\n 234:\t\t\tgoto error;\n 235:\t\n 236:\t\tret = mt76u_alloc_mcu_queue(\u0026dev-\u003emt76);\n 237:\t\tif (ret)\n 238:\t\t\tgoto error;\n 239:\t\n 240:\t\tret = mt76u_alloc_queues(\u0026dev-\u003emt76);\n 241:\t\tif (ret)\n 242:\t\t\tgoto error;\n 243:\t\n 244:\t\tret = mt792xu_dma_init(dev, false);\n 245:\t\tif (ret)\n 246:\t\t\tgoto error;\n 247:\t\n 248:\t\thw = mt76_hw(dev);\n 249:\t\t/* check hw sg support in order to enable AMSDU */\n 250:\t\thw-\u003emax_tx_fragments = mdev-\u003eusb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1;\n 251:\t\n 252:\t\tret = mt7925_register_device(dev);\n 253:\t\tif (ret)\n 254:\t\t\tgoto error;\n 255:\t\n 256:\t\treturn 0;\n 257:\t\n 258:\terror:\n 259:\t\tmt76u_queues_deinit(\u0026dev-\u003emt76);\n 260:\t\tmt792xu_reset_work_cleanup(dev);\n 261:\t\n 262:\t\tusb_set_intfdata(usb_intf, NULL);\n 263:\t\n 264:\t\tmt76_free_device(\u0026dev-\u003emt76);\n 265:\t\n 266:\t\treturn ret;\n 267:\t}\n 268:\t\n 269:\t#ifdef CONFIG_PM\n"
} |
| 19/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 35675 output: 47 thoughts: 40 Thoughts: Here's my summary, as if I were thinking these thoughts: **Diving into the MT7925 Driver Initialization** Okay, time to get my hands dirty. I need to take a look at how the MT7925 device is registered within the kernel. The most logical place to start is the `mt7925_register_device` function. I know it's probably located within the `drivers/net/wireless/mediatek/mt76/mt7925/init.c` file, so let's head there directly. This will be the entry point to understanding the device's setup procedure. I anticipate some interesting interactions with the core MT76 framework, and potentially some MTK-specific quirks. Gotta trace how the platform device is handled. |
| 20/2 | 2026/08/31 03:56 | tool | grepper |
0mArgs:{
"Expression": "mt7925_register_device",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/init.c=190=static void mt7925_init_work(struct work_struct *work)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-242-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:243:int mt7925_register_device(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-244-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-329-}\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:330:EXPORT_SYMBOL_GPL(mt7925_register_device);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=277=int __mt7925_start(struct mt792x_phy *phy);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:278:int mt7925_register_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-279-void mt7925_unregister_device(struct mt792x_dev *dev);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=528=static int mt7925_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-704-\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:705:\tret = mt7925_register_device(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-706-\tif (ret)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=150=static int mt7925u_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-251-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:252:\tret = mt7925_register_device(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-253-\tif (ret)\n"
} |
| 21/2 | 2026/08/31 03:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 36656 output: 50 thoughts: 40 Thoughts: Here's my take on the thought process, as requested: **Diving into the mt7925 Driver Initialization** Okay, so I need to get a handle on how this mt7925 wireless device is being brought up. I'm going straight to the source – the `drivers/net/wireless/mediatek/mt76/mt7925/init.c` file. Specifically, I want to trace the `mt7925_register_device` function. That name immediately suggests it's the critical entry point for registering the hardware with the kernel's network stack. I anticipate this function will handle things like probing the device, initializing its internal state, allocating resources (memory, IRQs, etc.), and ultimately making it known to the operating system as a network interface. I expect it'll be a fairly complex function, considering the sophistication of modern wireless chipsets, but a good starting point to understand the boot flow. I'm keen to see the exact sequence of operations within this function and how it integrates with the broader mt76 framework. Let's see what's in there. |
| 22/2 | 2026/08/31 03:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/init.c",
"FirstLine": 243,
"LineCount": 80
}Results: {
"Contents": " 243:\tint mt7925_register_device(struct mt792x_dev *dev)\n 244:\t{\n 245:\t\tstruct ieee80211_hw *hw = mt76_hw(dev);\n 246:\t\tint ret;\n 247:\t\n 248:\t\tdev-\u003ephy.dev = dev;\n 249:\t\tdev-\u003ephy.mt76 = \u0026dev-\u003emt76.phy;\n 250:\t\tdev-\u003emt76.phy.priv = \u0026dev-\u003ephy;\n 251:\t\tdev-\u003emt76.tx_worker.fn = mt792x_tx_worker;\n 252:\t\n 253:\t\tINIT_DELAYED_WORK(\u0026dev-\u003epm.ps_work, mt792x_pm_power_save_work);\n 254:\t\tINIT_DELAYED_WORK(\u0026dev-\u003emlo_pm_work, mt7925_mlo_pm_work);\n 255:\t\tINIT_WORK(\u0026dev-\u003epm.wake_work, mt792x_pm_wake_work);\n 256:\t\tspin_lock_init(\u0026dev-\u003epm.wake.lock);\n 257:\t\tmutex_init(\u0026dev-\u003epm.mutex);\n 258:\t\tinit_waitqueue_head(\u0026dev-\u003epm.wait);\n 259:\t\tinit_waitqueue_head(\u0026dev-\u003ewait);\n 260:\t\tspin_lock_init(\u0026dev-\u003epm.txq_lock);\n 261:\t\tINIT_DELAYED_WORK(\u0026dev-\u003emphy.mac_work, mt792x_mac_work);\n 262:\t\tINIT_DELAYED_WORK(\u0026dev-\u003ephy.scan_work, mt7925_scan_work);\n 263:\t\tINIT_DELAYED_WORK(\u0026dev-\u003ecoredump.work, mt7925_coredump_work);\n 264:\t#if IS_ENABLED(CONFIG_IPV6)\n 265:\t\tINIT_WORK(\u0026dev-\u003eipv6_ns_work, mt7925_set_ipv6_ns_work);\n 266:\t\tskb_queue_head_init(\u0026dev-\u003eipv6_ns_list);\n 267:\t#endif\n 268:\t\tskb_queue_head_init(\u0026dev-\u003ephy.scan_event_list);\n 269:\t\tskb_queue_head_init(\u0026dev-\u003ecoredump.msg_list);\n 270:\t\n 271:\t\tINIT_WORK(\u0026dev-\u003ereset_work, mt7925_mac_reset_work);\n 272:\t\tINIT_WORK(\u0026dev-\u003einit_work, mt7925_init_work);\n 273:\t\n 274:\t\tINIT_WORK(\u0026dev-\u003ephy.roc_work, mt7925_roc_work);\n 275:\t\ttimer_setup(\u0026dev-\u003ephy.roc_timer, mt792x_roc_timer, 0);\n 276:\t\tinit_waitqueue_head(\u0026dev-\u003ephy.roc_wait);\n 277:\t\n 278:\t\tdev-\u003epm.idle_timeout = MT792x_PM_TIMEOUT;\n 279:\t\tdev-\u003epm.stats.last_wake_event = jiffies;\n 280:\t\tdev-\u003epm.stats.last_doze_event = jiffies;\n 281:\t\t/* MT7927: runtime PM crashes BT firmware on the shared CONNINFRA domain */\n 282:\t\tif (!mt76_is_usb(\u0026dev-\u003emt76) \u0026\u0026 !is_mt7927(\u0026dev-\u003emt76)) {\n 283:\t\t\tdev-\u003epm.enable_user = true;\n 284:\t\t\tdev-\u003epm.enable = true;\n 285:\t\t\tdev-\u003epm.ds_enable_user = true;\n 286:\t\t\tdev-\u003epm.ds_enable = true;\n 287:\t\t}\n 288:\t\n 289:\t\tif (!mt76_is_mmio(\u0026dev-\u003emt76))\n 290:\t\t\thw-\u003eextra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;\n 291:\t\n 292:\t\tmt792x_init_acpi_sar(dev);\n 293:\t\n 294:\t\tret = mt792x_init_wcid(dev);\n 295:\t\tif (ret)\n 296:\t\t\treturn ret;\n 297:\t\n 298:\t\tret = mt792x_init_wiphy(hw);\n 299:\t\tif (ret)\n 300:\t\t\treturn ret;\n 301:\t\n 302:\t\thw-\u003ewiphy-\u003ereg_notifier = mt7925_regd_notifier;\n 303:\t\tdev-\u003emphy.sband_2g.sband.ht_cap.cap |=\n 304:\t\t\t\tIEEE80211_HT_CAP_LDPC_CODING |\n 305:\t\t\t\tIEEE80211_HT_CAP_MAX_AMSDU;\n 306:\t\tdev-\u003emphy.sband_2g.sband.ht_cap.ampdu_density =\n 307:\t\t\t\tIEEE80211_HT_MPDU_DENSITY_2;\n 308:\t\tdev-\u003emphy.sband_5g.sband.ht_cap.cap |=\n 309:\t\t\t\tIEEE80211_HT_CAP_LDPC_CODING |\n 310:\t\t\t\tIEEE80211_HT_CAP_MAX_AMSDU;\n 311:\t\tdev-\u003emphy.sband_2g.sband.ht_cap.ampdu_density =\n 312:\t\t\t\tIEEE80211_HT_MPDU_DENSITY_1;\n 313:\t\tdev-\u003emphy.sband_5g.sband.vht_cap.cap |=\n 314:\t\t\t\tIEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |\n 315:\t\t\t\tIEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |\n 316:\t\t\t\tIEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |\n 317:\t\t\t\tIEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |\n 318:\t\t\t\t(3 \u003c\u003c IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);\n 319:\t\tdev-\u003emphy.sband_5g.sband.vht_cap.cap |=\n 320:\t\t\t\tIEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |\n 321:\t\t\t\tIEEE80211_VHT_CAP_SHORT_GI_160;\n 322:\t\n"
} |
| 23/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 38755 output: 50 thoughts: 18 Thoughts: Okay, here's my attempt at summarizing the thought process, as if I were working through the code for `mt7925_register_device`, keeping in mind I'm an expert in this field. **Diving into mt7925_register_device** Alright, let's get into the heart of this `mt7925_register_device` function. I'm assuming, based on the name, this is where we're bringing the hardware to life, essentially integrating the MT7925 wireless chip with the system. Knowing MediaTek's driver structure, I expect to see the usual suspects: resource allocation, clock enabling, PHY initialization, register access setup, and ultimately, registration with the kernel's network stack. I'm looking for where they're handling things like: * **Platform Device Interaction:** How are they getting the device resources (IRQ, memory regions, etc.)? Are they using `platform_get_resource` or something similar? Are they correctly handling the potential for resource conflicts or errors? * **Clock Management:** MT7925 is likely clock-sensitive. I need to see how they're enabling and configuring the necessary clocks. Are they using the clock framework properly? Any special clock settings for the PHY or MAC? Any PLL configuration? * **DMA Setup:** Does this chip use DMA? If so, what DMA channels are being used, and how are they being configured? Any scatter/gather lists? Any DMA masks being set? I need to look for calls related to dma\_alloc\_coherent or dma\_set\_mask. * **Interrupt Handling:** How are they setting up the interrupt handler? Are they using the standard `request_irq` or the threaded interrupt handler? What's the interrupt masking scheme? Any potential interrupt storms to watch out for? * **MAC/PHY Initialization:** I want to see how they're bringing up the MAC and PHY. Are they doing the register sequence correctly for power-up and reset? Are they handling calibration properly? Are they loading firmware or blobs? * **Network Device Registration:** Finally, the key part: how are they registering this device as a network interface (likely using `alloc_netdev` or similar)? What flags are they setting? Are they properly attaching the device to the network stack and associating it with a virtual interface name? From a performance perspective, I'm expecting careful attention to interrupt latency, efficient DMA usage, and minimal overhead. I'll be keeping an eye out for potential bottlenecks or areas where they might be making unnecessary memory copies or context switches. I want to see this implemented in the most efficient manner possible. Let's see how they do it. |
| 24/2 | 2026/08/31 03:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/init.c",
"FirstLine": 320,
"LineCount": 20
}Results: {
"Contents": " 320:\t\t\t\tIEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |\n 321:\t\t\t\tIEEE80211_VHT_CAP_SHORT_GI_160;\n 322:\t\n 323:\t\tdev-\u003emphy.hw-\u003ewiphy-\u003eavailable_antennas_rx = dev-\u003emphy.chainmask;\n 324:\t\tdev-\u003emphy.hw-\u003ewiphy-\u003eavailable_antennas_tx = dev-\u003emphy.chainmask;\n 325:\t\n 326:\t\tqueue_work(system_percpu_wq, \u0026dev-\u003einit_work);\n 327:\t\n 328:\t\treturn 0;\n 329:\t}\n 330:\tEXPORT_SYMBOL_GPL(mt7925_register_device);\n"
} |
| 25/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 39629 output: 42 thoughts: 98 Thoughts: **Diving into the Initialization Sequence** Okay, so I'm tracing the initialization path for this driver. My eye catches `queue_work(system_percpu_wq, &dev->init_work);`. That's where it all begins, right? When `init_work` gets its turn on the worker queue, it triggers the function `mt7925_init_hardware(dev)`. That's the entry point! I know that from past experiences with this hardware family. Now, from `mt7925_init_hardware`, things get interesting. I see a call to `mt792x_mcu_init(dev)`. This is where the core MCU, likely responsible for much of the low-level wireless functionality, is being initialized. This is key, so that's where I need to focus my attention. I need to understand what `mt792x_mcu_init` does. Let's dig in and see how the MCU is brought up and configured. This is where the real magic happens, so it's a critical area to examine. |
| 26/2 | 2026/08/31 03:57 | tool | grepper |
0mArgs:{
"Expression": "mt792x_mcu_init",
"PathPrefix": "drivers/net/wireless/mediatek/mt76"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7921/init.c=84=static int __mt7921_init_hardware(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7921/init.c-91-\tmt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);\ndrivers/net/wireless/mediatek/mt76/mt7921/init.c:92:\tret = mt792x_mcu_init(dev);\ndrivers/net/wireless/mediatek/mt76/mt7921/init.c-93-\tif (ret)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c=100=static int __mt7925_init_hardware(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-103-\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:104:\tret = mt792x_mcu_init(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-105-\tif (ret)\n--\ndrivers/net/wireless/mediatek/mt76/mt792x.h=262=struct mt792x_dma_layout {\n--\ndrivers/net/wireless/mediatek/mt76/mt792x.h-275-#define mt792x_dev_reset(dev)\t\t((dev)-\u003ehif_ops-\u003ereset(dev))\ndrivers/net/wireless/mediatek/mt76/mt792x.h:276:#define mt792x_mcu_init(dev)\t\t((dev)-\u003ehif_ops-\u003emcu_init(dev))\ndrivers/net/wireless/mediatek/mt76/mt792x.h-277-#define __mt792x_mcu_drv_pmctrl(dev)\t((dev)-\u003ehif_ops-\u003edrv_own(dev))\n"
} |
| 27/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 40569 output: 43 thoughts: 38 Thoughts: Here's my take on the thought process: **Diving into the Initialization Sequence** Okay, so the program flow has landed on `mt7925u_mcu_init`. That's where it's starting, so it's the critical entry point. Given the naming convention, it's pretty clear this is a MediaTek Wi-Fi chip and the initialization of its MCU. Now, I need to understand what's happening within that function. I'll need to locate the definition of `mt7925u_mcu_init` immediately to see what configuration and setup steps are performed. Time to dig in! Let's see what secrets this function holds. |
| 28/2 | 2026/08/31 03:57 | tool | grepper |
0mArgs:{
"Expression": "mt7925u_mcu_init",
"PathPrefix": "drivers/net/wireless/mediatek/mt76"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c=27=mt7925u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-55-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:56:static int mt7925u_mcu_init(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-57-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=150=static int mt7925u_probe(struct usb_interface *usb_intf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-170-\tstatic const struct mt792x_hif_ops hif_ops = {\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:171:\t\t.mcu_init = mt7925u_mcu_init,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-172-\t\t.init_reset = mt792xu_init_reset,\n"
} |
| 29/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 41170 output: 49 thoughts: 17 Thoughts: Okay, here's my interpretation of what's going on, framed as a first-person expert perspective: **Initial Thoughts on `mt7925u_mcu_init`** Alright, let's dive into this `mt7925u_mcu_init` function. The naming convention immediately tells me this is likely related to the MediaTek MT7925U Wi-Fi chip, specifically the MCU (Microcontroller Unit) initialization. My mind immediately starts running through the typical initialization phases I'd expect: clock setup, power management, potentially loading firmware, setting up interrupts, and configuring any external interfaces the MCU uses. I anticipate this function being the gateway to bringing the Wi-Fi chip's low-level functionality online. I'll be looking closely for the following: How does it handle potential hardware resets or initial boot-up sequences? Are there any specific register accesses that jump out as crucial for bringing up the radio? I'll probably be checking for any error handling mechanisms – how does it deal with failures in the initialization process? I hope there are some well-placed comments. |
| 30/2 | 2026/08/31 03:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c",
"FirstLine": 56,
"LineCount": 40
}Results: {
"Contents": " 56:\tstatic int mt7925u_mcu_init(struct mt792x_dev *dev)\n 57:\t{\n 58:\t\tstatic const struct mt76_mcu_ops mcu_ops = {\n 59:\t\t\t.headroom = MT_SDIO_HDR_SIZE +\n 60:\t\t\t\t sizeof(struct mt76_connac2_mcu_txd),\n 61:\t\t\t.tailroom = MT_USB_TAIL_SIZE,\n 62:\t\t\t.mcu_skb_send_msg = mt7925u_mcu_send_message,\n 63:\t\t\t.mcu_parse_response = mt7925_mcu_parse_response,\n 64:\t\t};\n 65:\t\tint ret;\n 66:\t\n 67:\t\tdev-\u003emt76.mcu_ops = \u0026mcu_ops;\n 68:\t\n 69:\t\tmt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);\n 70:\t\tret = mt7925_run_firmware(dev);\n 71:\t\tif (ret)\n 72:\t\t\treturn ret;\n 73:\t\n 74:\t\tset_bit(MT76_STATE_MCU_RUNNING, \u0026dev-\u003emphy.state);\n 75:\t\tmt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);\n 76:\t\n 77:\t\treturn 0;\n 78:\t}\n 79:\t\n 80:\tstatic int mt7925u_mac_reset(struct mt792x_dev *dev)\n 81:\t{\n 82:\t\tint err;\n 83:\t\n 84:\t\tif (atomic_read(\u0026dev-\u003emt76.bus_hung))\n 85:\t\t\treturn 0;\n 86:\t\n 87:\t\tmt792xu_reset_on_bus_error(dev);\n 88:\t\tif (atomic_read(\u0026dev-\u003emt76.bus_hung))\n 89:\t\t\treturn 0;\n 90:\t\n 91:\t\tmt76_txq_schedule_all(\u0026dev-\u003emphy);\n 92:\t\tmt76_worker_disable(\u0026dev-\u003emt76.tx_worker);\n 93:\t\n 94:\t\tset_bit(MT76_RESET, \u0026dev-\u003emphy.state);\n 95:\t\tset_bit(MT76_MCU_RESET, \u0026dev-\u003emphy.state);\n"
} |
| 31/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 42138 output: 48 thoughts: 673 Thoughts: **Analyzing the Fuzzing Potential of This Patch** Okay, let's break this down. We're looking at `mt7925_run_firmware(dev)` and the associated changes. My first thought is: a USB device gets plugged in, firmware loads, communication happens, standard stuff. But then I need to stop and really *look* at the patch. This patch adds a few things: some debugfs read handlers – `mt792x_stats` and some related functions to get MIB info, link quality, rates, and stats. It also includes some auto-rate printing and TX rate decoding helpers. And of course, there's the creation of the "stats" debugfs file within `mt7925_init_debugfs`. Now, the important question: is any of this reachable in a syzkaller/fuzzing context? I know the fuzzing instructions pretty well. I need to go through the checklist: Does this fall under any of the "WorthFuzzing=false" criteria? I've got to ensure the patch is worth fuzzing. My immediate thought is: is this *vendor-specific*? Is `mt7925` a MediaTek Wi-Fi driver? Yes, it is. And I know it has PCI *and* USB variants (`MT7925E` and `MT7925U`, respectively). The key question is if it is reachable via software-emulated hardware. Okay, let's think about this. Syzkaller, when fuzzing the Linux kernel, is known to create virtual USB devices (like the USB Raw Gadget), to test USB drivers. And since this is a USB-based device (`MT7925U` is USB), there's a good chance of it binding to a virtual USB device. So the question is if the virtual device binds to the driver, or if it isn't reachable with this kind of hardware emulation. Okay, let's confirm this: Is there a device table for USB in the source code? Yes! Let's check `mt7925u_device_table` in `drivers/net/wireless/mediatek/mt76/mt7925/usb.c` to confirm. |
| 32/2 | 2026/08/31 03:57 | tool | grepper |
0mArgs:{
"Expression": "mt7925u_device_table",
"PathPrefix": "drivers/net/wireless/mediatek/mt76/mt7925"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/usb.c-11-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:12:static const struct usb_device_id mt7925u_device_table[] = {\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-13-\t{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x6639, 0xff, 0xff, 0xff),\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=303=static int mt7925u_resume(struct usb_interface *intf)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-350-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:351:MODULE_DEVICE_TABLE(usb, mt7925u_device_table);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-352-MODULE_FIRMWARE(MT7925_FIRMWARE_WM);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=355=static struct usb_driver mt7925u_driver = {\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-356-\t.name\t\t= KBUILD_MODNAME,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:357:\t.id_table\t= mt7925u_device_table,\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-358-\t.probe\t\t= mt7925u_probe,\n"
} |
| 33/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 43846 output: 145 thoughts: 500 Thoughts: **Analyzing the `mt7925u` USB Driver Patch** Okay, so `mt7925u` is indeed a USB driver, specifically with the `USB_DEVICE_AND_INTERFACE_INFO` of `0x0e8d, 0x6639`. But I need to understand the *impact* of this specific patch. What's it actually *doing*? Right, let's examine the code changes. Ah, it seems this patch introduces a debugfs file, specifically `/sys/kernel/debug/.../stats`, and a set of functions to read debug statistics via that file, `mt792x_stats`. Now, the important part. What new *functions* are added specifically within `stats.c` and `debugfs.c`? Okay, let's break down `stats.c`: There's `mt7925_get_ap_sta_rec_idx_iter` (static), then `mt7925_get_ap_sta_rec_idx`, `mt7925_print_last_tx_rate`, `mt7925_wtbl_get_sgi`, `mt7925_wtbl_get_ldpc`, `mt792x_mcu_get_stat`, `mt7925_mcu_get_mib_info`, `mt7925_hw_rate_ofdm_str`, `mt792x_mcu_get_wtbl_rate`, and `mt7925_mcu_get_link_quality` (all exported). Then in `debugfs.c` we have `mt7925_dump_auto_rate_table` (static) and, of course, `mt792x_stats` itself. Now the crucial question: are any of those functions *only* called from within `mt792x_stats` - meaning, are they purely for use in the debugfs file? I need to verify that this is the sole entry point, or if these are now exported, possibly for use in another context! It’s time to search the kernel source and verify how and where these functions are actually used. |
| 34/2 | 2026/08/31 03:57 | tool | grepper |
0mArgs:{
"Expression": "mt792x_mcu_get_stat|mt7925_mcu_get_mib_info|mt7925_mcu_get_link_quality|mt792x_mcu_get_wtbl_rate|mt7925_print_last_tx_rate|mt7925_wtbl_get_sgi|mt7925_wtbl_get_ldpc|mt7925_hw_rate_ofdm_str|mt7925_get_ap_sta_rec_idx"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c=327=mt7925_dump_auto_rate_table(struct seq_file *s,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-344-\t\tu8 ersu106t = MT7925_HW_RATE_TO_106T(rate_code);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:345:\t\tu8 sgi = mt7925_wtbl_get_sgi(wr, txmode, fcap);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:346:\t\tu8 ldpc = mt7925_wtbl_get_ldpc(wr, txmode);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-347-\t\tconst char *mode_str = \"N/A\";\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-364-\t\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:365:\t\t\tseq_printf(s, \"%s, \", mt7925_hw_rate_ofdm_str(rate));\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-366-\t\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c=416=static int mt792x_stats(struct seq_file *s, void *data)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-446-\tmt792x_mutex_acquire(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:447:\tret = mt792x_mcu_get_stat(dev, stats);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-448-\tmt792x_mutex_release(dev);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-453-\tmt792x_mutex_acquire(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:454:\tret = mt7925_mcu_get_mib_info(dev,\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-455-\t\t\t\t band_idx,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-464-\tmt792x_mutex_acquire(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:465:\tret = mt7925_mcu_get_link_quality(dev,\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-466-\t\t\t\t\t stats-\u003ebss_idx,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-476-\tmt792x_mutex_acquire(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:477:\tif (!mt792x_mcu_get_wtbl_rate(dev, stats-\u003ewtbl_idx, \u0026wtbl_rate))\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-478-\t\twtbl_rate_valid = true;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-557-\t/* Decode the TX Vector BBP latch to show the current TX MCS rate */\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:558:\tmt7925_print_last_tx_rate(s, stats-\u003etx_vector[band_idx].txv);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-559-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c=108=static void\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:109:mt7925_get_ap_sta_rec_idx_iter(void *data, u8 *mac,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-110-\t\t\t struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c=133=int\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:134:mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx)\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-135-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-143-\t\t\t\t\t IEEE80211_IFACE_ITER_RESUME_ALL,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:144:\t\t\t\t\t mt7925_get_ap_sta_rec_idx_iter,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-145-\t\t\t\t\t \u0026lookup);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c=159=void\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:160:mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3])\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-161-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-207-\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:208:\t\tseq_printf(s, \"%s, \", mt7925_hw_rate_ofdm_str(rate));\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-209-\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c=253=u8\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:254:mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap)\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-255-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c=284=u8\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:285:mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode)\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-286-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-306-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:307:int mt792x_mcu_get_stat(struct mt792x_dev *dev,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-308-\t\t\tstruct mt7925_sta_stats *stats)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-320-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:321:\tret = mt7925_get_ap_sta_rec_idx(dev, \u0026req.sta_rec_idx);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-322-\tif (ret)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-365-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:366:int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-367-\t\t\t const u32 *counters, u8 counter_num,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-453-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:454:char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx)\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-455-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-472-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:473:/* mt792x_mcu_get_wtbl_rate - fetch the firmware auto-rate table for a WCID\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-474- * @dev:\tdevice\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-482- */\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:483:int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-484-\t\t\t struct mt7925_wtbl_rate *rate)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-524-/**\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:525: * mt7925_mcu_get_link_quality - query RSSI and TX link speed for a band\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-526- * @dev:\tdevice\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-534- */\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c:535:int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.c-536-\t\t\t\ts8 *rssi, u32 *tx_link_speed_kbps)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h=270=int\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:271:mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-272-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h=273=void\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:274:mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3]);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-275-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h=276=u8\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:277:mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-278-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h=279=u8\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:280:mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-281-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:282:char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-283-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:284:int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-285-\t\t\t struct mt7925_wtbl_rate *rate);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-286-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:287:int mt792x_mcu_get_stat(struct mt792x_dev *dev,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-288-\t\t\tstruct mt7925_sta_stats *stats);\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-289-\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:290:int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-291-\t\t\t const u32 *counters, u8 counter_num,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-305- */\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h:306:int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,\ndrivers/net/wireless/mediatek/mt76/mt7925/stats.h-307-\t\t\t\ts8 *rssi, u32 *tx_link_speed_kbps);\n"
} |
| 35/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 49131 output: 42 thoughts: 231 Thoughts: **My Assessment of the Debugfs Vulnerability** Okay, so the new code is only activated when someone reads the `/sys/kernel/debug/.../stats` debugfs file. That's the key. Now I need to figure out if that's reachable in a fuzzing environment. The usual attack vector with debugfs is to fuzz the operations themselves after the driver probe successfully executes. So, if the debugfs file exists, then it's vulnerable. The next question is, can the mt7925 driver probe complete in a fuzzing setup? We're talking specifically about the MT7925 device driver, and I need to consider both the PCI and USB variants. Let's look at `mt7925u_probe` and `mt7925_pci_probe`. For the PCI version (`mt7925_pci_probe`), it looks like we need actual MediaTek MT7925 PCI hardware (with a specific Vendor ID, like 0x14c3). Hmm, and that's usually vendor-specific, which means it likely *isn't* emulated in standard QEMU. That's good. So, let's look at the USB version (`mt7925u_probe`). I need to understand what happens during the probe, and how `mt7925_run_firmware(dev)` comes into play. I'll check those functions to understand the process. |
| 36/2 | 2026/08/31 03:57 | tool | grepper |
0mArgs:{
"Expression": "mt7925_run_firmware",
"PathPrefix": "drivers/net/wireless/mediatek/mt76"
}Results: {
"Output": "drivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1188=EXPORT_SYMBOL_GPL(mt7925_mcu_set_thermal_protect);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1189-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1190:int mt7925_run_firmware(struct mt792x_dev *dev)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1191-{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1208-}\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1209:EXPORT_SYMBOL_GPL(mt7925_run_firmware);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1210-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=279=void mt7925_unregister_device(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:280:int mt7925_run_firmware(struct mt792x_dev *dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-281-int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c=71=int mt7925e_mac_reset(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c-133-\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c:134:\terr = mt7925_run_firmware(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c-135-\tif (err)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c=27=int mt7925e_mcu_init(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c-47-\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c:48:\terr = mt7925_run_firmware(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c-49-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=56=static int mt7925u_mcu_init(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-69-\tmt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:70:\tret = mt7925_run_firmware(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-71-\tif (ret)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c=80=static int mt7925u_mac_reset(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-120-\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c:121:\terr = mt7925_run_firmware(dev);\ndrivers/net/wireless/mediatek/mt76/mt7925/usb.c-122-\tif (err)\n"
} |
| 37/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 50862 output: 52 thoughts: 42 Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of embedded systems and driver development: **Diving into the MT7925 Firmware Initialization** Alright, my internal radar just pinged. I'm thinking I need to understand how this MT7925 chipset, specifically its firmware loading, actually works. The function call `mt7925_run_firmware` is what I'm focused on right now, and the likely implementation will be found within `drivers/net/wireless/mediatek/mt76/mt7925/mcu.c`. That file name and path are practically burned into my memory by now. It's the Mediatek 76 wireless driver, and the MT7925 is a specific variant. So, this `mcu.c` file is where the lower-level Media Control Unit (MCU) interactions and firmware execution magic is most likely hidden. Time to crack open that source file and get a handle on the boot-up sequence and any potential quirks. I need to figure out what parameters are being passed, what the return values mean, and how this function coordinates with the rest of the driver. Let's see what's really happening under the hood. |
| 38/2 | 2026/08/31 03:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/mcu.c",
"FirstLine": 1190,
"LineCount": 30
}Results: {
"Contents": "1190:\tint mt7925_run_firmware(struct mt792x_dev *dev)\n1191:\t{\n1192:\t\tint err;\n1193:\t\n1194:\t\terr = mt792x_load_firmware(dev);\n1195:\t\tif (err)\n1196:\t\t\treturn err;\n1197:\t\n1198:\t\terr = mt7925_mcu_get_nic_capability(dev);\n1199:\t\tif (err)\n1200:\t\t\treturn err;\n1201:\t\n1202:\t\terr = mt7925_load_clc(dev, mt792x_ram_name(dev));\n1203:\t\tif (err)\n1204:\t\t\treturn err;\n1205:\t\tset_bit(MT76_STATE_MCU_RUNNING, \u0026dev-\u003emphy.state);\n1206:\t\n1207:\t\treturn mt7925_mcu_fw_log_2_host(dev, 1);\n1208:\t}\n1209:\tEXPORT_SYMBOL_GPL(mt7925_run_firmware);\n1210:\t\n1211:\tstatic void\n1212:\tmt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,\n1213:\t\t\t\t struct ieee80211_vif *vif,\n1214:\t\t\t\t struct mt792x_link_sta *mlink)\n1215:\t{\n1216:\t\tstruct sta_rec_hdr_trans *hdr_trans;\n1217:\t\tstruct mt76_wcid *wcid;\n1218:\t\tstruct tlv *tlv;\n1219:\t\n"
} |
| 39/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 51714 output: 37 thoughts: 1939 Thoughts: **Fuzzing Feasibility of MediaTek MT7925 USB Driver Stats** Okay, here's the breakdown of my thought process: I need to determine if this patch, specifically the code within `debugfs.c` related to the MediaTek MT7925 driver, is worth fuzzing with syzkaller. Let's consider the relevant aspects. First, I need to understand the environment. We're talking about virtual environments like QEMU with USB gadget setups or similar, and whether `mt7925u` is reachable in those configurations. `mac80211_hwsim` is out, it isn't relevant to this hardware. Syzkaller's USB fuzzing capabilities are what I'm looking at, specifically how it uses `syz_usb_connect` with `dummy_hcd` or `raw-gadget`. The core question is whether the MT7925 USB driver can be connected and interacted with in QEMU. I need to confirm if MT7925 needs physical hardware or can be simulated. I've noted that this patch is related to `/sys/kernel/debug/.../stats`, which is created through a debugfs entry in `debugfs.c`. This entry is linked to several functions: `mt792x_stats`, `mt792x_mcu_get_stat`, `mt7925_mcu_get_mib_info`, and others that read stats. The crucial point is that this debugfs entry leads to interaction with the MT7925's MCU and the retrieval of statistics, like MIB information, link quality, and wireless table data. This involves sending commands to the MCU and parsing responses. Now, let's assess whether this code meets the "WorthFuzzing=false" criteria based on the project's fuzzing guidelines. Specifically, the question is whether this code path is *impossible to reach* in a virtualized environment. The guidelines *exclude* vendor-specific PCIe, SmartNIC, or GPU drivers that require physical hardware. But, the MT7925 does *not* seem to be in this category. It has a USB driver, `CONFIG_MT7925U`. Syzkaller *can* fuzz USB drivers, providing descriptors, control messages, and firmware responses. Therefore, this code path seems reachable, particularly through the USB interface in QEMU. A key point is that Syzkaller can, and *does*, fuzz debugfs. It opens and reads/writes from files in `/sys/kernel/debug/`. So, reading `/sys/kernel/debug/.../stats` is a realistic fuzzing target. Let's dissect what happens when `/sys/kernel/debug/.../stats` is read: It executes `mt792x_stats`, which, in turn, calls various MCU interaction functions and parses the responses, like `mt792x_mcu_get_stat`, `mt7925_mcu_get_mib_info`, etc. Parsing responses involves skb unpacking, le16/le32 handling, TLV stream parsing, and bitfield decoding. This looks complex. Specifically, in `mt7925_mcu_get_mib_info`, there's TLV stream parsing inside a `while` loop, with checks for length and offsets. There are other functions that decode rate codes, potentially involving bitfield manipulations. This intricate parsing logic represents a potential attack surface. Therefore, because this driver is accessible through syzkaller's USB fuzzing and debugfs access, and because this code involves parsing data from the MCU, and it's not vendor-specific PCIe hardware, it seems worth fuzzing. |
| 40/2 | 2026/08/31 03:57 | tool | grepper |
0mArgs:{
"Expression": "MT7925",
"PathPrefix": "drivers/net/wireless/mediatek/mt76"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 966 lines.\nUse more precise expression if possible.\n\ndrivers/net/wireless/mediatek/mt76/Makefile=51=obj-$(CONFIG_MT7996E) += mt7996/\ndrivers/net/wireless/mediatek/mt76/Makefile:52:obj-$(CONFIG_MT7925_COMMON) += mt7925/\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-1-# SPDX-License-Identifier: BSD-3-Clause-Clear\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:2:config MT7925_COMMON\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-3-\ttristate\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-6-\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:7:config MT7925E\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:8:\ttristate \"MediaTek MT7925E (PCIe) support\"\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:9:\tselect MT7925_COMMON\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-10-\tdepends on MAC80211\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-12-\thelp\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:13:\t This adds support for MT7925-based wireless PCIe devices,\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-14-\t which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-18-\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:19:config MT7925U\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:20:\ttristate \"MediaTek MT7925U (USB) support\"\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-21-\tselect MT792x_USB\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:22:\tselect MT7925_COMMON\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-23-\tdepends on MAC80211\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-25-\thelp\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig:26:\t This adds support for MT7925-based wireless USB devices,\ndrivers/net/wireless/mediatek/mt76/mt7925/Kconfig-27-\t which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/Makefile-2-\ndrivers/net/wireless/mediatek/mt76/mt7925/Makefile:3:obj-$(CONFIG_MT7925_COMMON) += mt7925-common.o\ndrivers/net/wireless/mediatek/mt76/mt7925/Makefile:4:obj-$(CONFIG_MT7925E) += mt7925e.o\ndrivers/net/wireless/mediatek/mt76/mt7925/Makefile:5:obj-$(CONFIG_MT7925U) += mt7925u.o\ndrivers/net/wireless/mediatek/mt76/mt7925/Makefile-6-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c=327=mt7925_dump_auto_rate_table(struct seq_file *s,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-336-\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:337:\tfor (i = 0; i \u003c MT7925_AUTO_RATE_NUM; i++) {\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-338-\t\tu16 rate_code = le16_to_cpu(wr-\u003erate_code[i]);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:339:\t\tu8 txmode = MT7925_HW_RATE_TO_MODE(rate_code);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:340:\t\tu8 rate = MT7925_HW_RATE_TO_MCS(rate_code);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:341:\t\tu8 nsts = MT7925_HW_RATE_TO_NSS(rate_code) + 1;\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:342:\t\tu8 stbc = MT7925_HW_RATE_TO_STBC(rate_code);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:343:\t\tu8 dcm = MT7925_HW_RATE_TO_DCM(rate_code);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:344:\t\tu8 ersu106t = MT7925_HW_RATE_TO_106T(rate_code);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-345-\t\tu8 sgi = mt7925_wtbl_get_sgi(wr, txmode, fcap);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-349-\t\tif (dcm)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:350:\t\t\trate = MT7925_HW_RATE_UNMASK_DCM(rate);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-351-\t\tif (ersu106t)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:352:\t\t\trate = MT7925_HW_RATE_UNMASK_106T(rate);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-353-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-360-\t\t/* rate/MCS field */\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:361:\t\tif (txmode == MT7925_TX_RATE_MODE_CCK)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-362-\t\t\tseq_printf(s, \"%s, \",\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-363-\t\t\t\t mt7925_tx_rate_cck_str[rate \u0026 0x3]);\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:364:\t\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-365-\t\t\tseq_printf(s, \"%s, \", mt7925_hw_rate_ofdm_str(rate));\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:366:\t\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:367:\t\t\t txmode == MT7925_TX_RATE_MODE_HTGF)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-368-\t\t\tseq_printf(s, \"MCS%d, \", rate);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-373-\t\t/* bandwidth: mirror the CCK/OFDM -\u003e BW20 and cbrn handling */\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:374:\t\tif (txmode == MT7925_TX_RATE_MODE_CCK ||\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:375:\t\t txmode == MT7925_TX_RATE_MODE_OFDM)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-376-\t\t\tseq_printf(s, \"%s, \", mt7925_tx_rate_bw_str[0]);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-379-\t\t\t\t fcap \u003c 5 ?\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:380:\t\t\t\t (fcap \u003e MT7925_BW_20 ?\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-381-\t\t\t\t mt7925_tx_rate_bw_str[fcap - 1] :\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-389-\t\t/* GI / preamble */\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:390:\t\tif (txmode == MT7925_TX_RATE_MODE_CCK)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-391-\t\t\tseq_printf(s, \"%s, \", rate \u003c 4 ? \"LP\" : \"SP\");\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:392:\t\telse if (txmode == MT7925_TX_RATE_MODE_OFDM)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-393-\t\t\t; /* OFDM has no GI/preamble to print */\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:394:\t\telse if (txmode == MT7925_TX_RATE_MODE_HTMIX ||\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:395:\t\t\t txmode == MT7925_TX_RATE_MODE_HTGF ||\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:396:\t\t\t txmode == MT7925_TX_RATE_MODE_VHT ||\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:397:\t\t\t txmode == MT7925_TX_RATE_MODE_PLR)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-398-\t\t\tseq_printf(s, \"%s, \", sgi == 0 ? \"LGI\" : \"SGI\");\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-409-\t\t\t (ldpc == 0 ||\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:410:\t\t\t txmode == MT7925_TX_RATE_MODE_CCK ||\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:411:\t\t\t txmode == MT7925_TX_RATE_MODE_OFDM) ?\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-412-\t\t\t \"BCC\" : \"LDPC\");\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c=416=static int mt792x_stats(struct seq_file *s, void *data)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-437-\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c:438:\tif (band_idx \u003e= MT7925_STA_STATS_BAND_NUM)\ndrivers/net/wireless/mediatek/mt76/mt7925/debugfs.c-439-\t\treturn -EINVAL;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.c=13=bool mt7925_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.c-19-\telse\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.c:20:\t\twtbl_update = MT7925_WTBL_UPDATE;\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.c-21-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h-3-\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h:4:#ifndef __MT7925_MAC_H\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h:5:#define __MT7925_MAC_H\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h-6-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h=15=static inline u32 mt7925_mac_wtbl_lmac_addr(struct mt792x_dev *dev, u16 wcid, u8 dw)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h-21-\telse\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h:22:\t\twdu_cr = MT7925_WTBLON_TOP_WDUCR;\ndrivers/net/wireless/mediatek/mt76/mt7925/mac.h-23-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=624=static int mt7925_remain_on_channel(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-635-\terr = mt7925_set_roc(phy, \u0026mvif-\u003ebss_conf,\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:636:\t\t\t chan, duration, MT7925_ROC_REQ_ROC);\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-637-\tmt792x_mutex_release(phy-\u003edev);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=854=static void mt7925_configure_filter(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-858-{\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:859:#define MT7925_FILTER_FCSFAIL BIT(2)\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:860:#define MT7925_FILTER_CONTROL BIT(5)\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:861:#define MT7925_FILTER_OTHER_BSS BIT(6)\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:862:#define MT7925_FILTER_ENABLE BIT(31)\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-863-\tstruct mt792x_dev *dev = mt792x_hw_dev(hw);\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:864:\tu32 flags = MT7925_FILTER_ENABLE;\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-865-\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:866:#define MT7925_FILTER(_fif, _type) do {\t\t\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-867-\t\tif (*total_flags \u0026 (_fif))\t\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:868:\t\t\tflags |= MT7925_FILTER_##_type;\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-869-\t} while (0)\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-870-\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:871:\tMT7925_FILTER(FIF_FCSFAIL, FCSFAIL);\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:872:\tMT7925_FILTER(FIF_CONTROL, CONTROL);\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:873:\tMT7925_FILTER(FIF_OTHER_BSS, OTHER_BSS);\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-874-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=883=mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-897-\t\t/* must odd index */\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:898:\t\tidx = MT7925_BEACON_RATES_TBL + 2 * (mvif-\u003eidx % 20);\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-899-\t\tmt7925_mac_set_fixed_rate_table(dev, idx, rate);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=2070=static void mt7925_mgd_prepare_tx(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-2081-\t\t mvif-\u003ebss_conf.mt76.ctx-\u003edef.chan, duration,\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:2082:\t\t MT7925_ROC_REQ_JOIN);\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-2083-\tmt792x_mutex_release(dev);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=2461=void mt7925_csa_work(struct work_struct *work)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-2484-\tlink_conf = \u0026vif-\u003ebss_conf;\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:2485:\troc_rtype = MT7925_ROC_REQ_JOIN;\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-2486-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=2792=MODULE_AUTHOR(\"Deren Wu \u003cderen.wu@mediatek.com\u003e\");\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:2793:MODULE_DESCRIPTION(\"MediaTek MT7925 core driver\");\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-2794-MODULE_LICENSE(\"Dual BSD/GPL\");\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-13-#define MT_STA_BFEE\t\t\tBIT(1)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:14:#define MT7925_WOW_PATTERN_NEW_FW_DATE\t\"20260414153105\"\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-15-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=233=static bool mt7925_mcu_wow_pattern_old_tlv(struct mt76_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-245-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:246:\treturn strncmp(build_date, MT7925_WOW_PATTERN_NEW_FW_DATE,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:247:\t\t strlen(MT7925_WOW_PATTERN_NEW_FW_DATE)) \u003c 0;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-248-}\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=251=mt7925_mcu_set_wow_pattern(struct mt76_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-269-\ttlv_len = old_tlv ? sizeof(struct mt7925_wow_pattern_tlv) :\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:270:\t\t\t MT7925_WOW_PATTERN_TLV_V2_SIZE;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-271-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=359=static void mt7925_mcu_roc_handle_grant(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-370-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:371:\tif (grant-\u003ereqtype == MT7925_ROC_REQ_ROC)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-372-\t\tieee80211_ready_on_channel(hw);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:373:\telse if (grant-\u003ereqtype == MT7925_ROC_REQ_JOIN)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-374-\t\tieee80211_iterate_active_interfaces_atomic(hw,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=826=static int mt7925_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-835-\t\t__le32 valid;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:836:\t\tu8 data[MT7925_EEPROM_BLOCK_SIZE];\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-837-\t} __packed req = {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-840-\t\t.addr = cpu_to_le32(round_down(offset,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:841:\t\t\t\t MT7925_EEPROM_BLOCK_SIZE)),\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-842-\t};\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-866-\tres = (struct evt *)skb-\u003edata;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:867:\t*val = res-\u003edata[offset % MT7925_EEPROM_BLOCK_SIZE];\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-868-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1246=int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1254-\t\t\t\t\t \u0026mlink-\u003ewcid,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1255:\t\t\t\t\t MT7925_STA_UPDATE_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1256-\tif (IS_ERR(skb))\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1403=int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1414-\tskb = __mt76_connac_mcu_alloc_sta_req(dev, \u0026mconf-\u003emt76, wcid,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1415:\t\t\t\t\t MT7925_STA_UPDATE_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1416-\tif (IS_ERR(skb))\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=1428=int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1489-\t IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS))\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1490:\t\ttype = is_AG_band ? MT7925_ROC_REQ_MLSR_AG :\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1491:\t\t\t\t MT7925_ROC_REQ_MLSR_AA;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1492-\telse\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1493:\t\ttype = MT7925_ROC_REQ_JOIN;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1494-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1517-\t\t */\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:1518:\t\treq.roc[i].dbdcband = type == MT7925_ROC_REQ_JOIN ? 0xfe : 0xff;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-1519-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2124=mt7925_mcu_sta_cmd(struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2137-\tskb = __mt76_connac_mcu_alloc_sta_req(dev, \u0026mconf-\u003emt76, info-\u003ewcid,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2138:\t\t\t\t\t MT7925_STA_UPDATE_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2139-\tif (IS_ERR(skb))\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2212=int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2215-{\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2216:#define MT7925_FIF_BIT_CLR\t\tBIT(1)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2217:#define MT7925_FIF_BIT_SET\t\tBIT(0)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2218-\tint err = 0;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2225-\t\treturn mt7925_mcu_set_rxfilter(dev, 0,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2226:\t\t\t\t\t MT7925_FIF_BIT_SET,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2227-\t\t\t\t\t MT_WF_RFCR_DROP_OTHER_BEACON);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2234-\treturn mt7925_mcu_set_rxfilter(dev, 0,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2235:\t\t\t\t MT7925_FIF_BIT_CLR,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2236-\t\t\t\t MT_WF_RFCR_DROP_OTHER_BEACON);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2583=int mt7925_mcu_set_eht_pp(struct mt76_phy *phy, struct mt76_vif_link *mvif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2589-\tskb = __mt7925_mcu_alloc_bss_req(phy-\u003edev, mvif,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2590:\t\t\t\t\t MT7925_BSS_UPDATE_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2591-\tif (IS_ERR(skb))\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2600=int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2606-\tskb = __mt7925_mcu_alloc_bss_req(phy-\u003edev, mvif,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2607:\t\t\t\t\t MT7925_BSS_UPDATE_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2608-\tif (IS_ERR(skb))\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2989=int mt7925_mcu_set_timing(struct mt792x_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2996-\tskb = __mt7925_mcu_alloc_bss_req(\u0026dev-\u003emt76, \u0026mconf-\u003emt76,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2997:\t\t\t\t\t MT7925_BSS_UPDATE_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2998-\tif (IS_ERR(skb))\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=3063=int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3076-\tskb = __mt7925_mcu_alloc_bss_req(\u0026dev-\u003emt76, \u0026mconf-\u003emt76,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3077:\t\t\t\t\t MT7925_BSS_UPDATE_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3078-\tif (IS_ERR(skb))\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=3215=int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3238-\tmax_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) +\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3239:\t\t sizeof(*bssid) * MT7925_RNR_SCAN_MAX_BSSIDS +\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3240-\t\t sizeof(*chan_info) + sizeof(*misc) + sizeof(*ie) +\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3263-\t\t\tcontinue;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3264:\t\tif (i \u003e= MT7925_RNR_SCAN_MAX_BSSIDS)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3265-\t\t\tbreak;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3280-\t\tfor (j = 0; j \u003c mdev-\u003ernr.bssid_num; j++) {\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3281:\t\t\tif (j \u003e= MT7925_RNR_SCAN_MAX_BSSIDS)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3282-\t\t\t\tbreak;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3289-\t\t\tbssid-\u003ematch_ch = mdev-\u003ernr.channel[j];\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3290:\t\t\tbssid-\u003ematch_ssid_ind = MT7925_RNR_SCAN_MAX_BSSIDS;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:3291:\t\t\tbssid-\u003ematch_short_ssid_ind = MT7925_RNR_SCAN_MAX_BSSIDS;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-3292-\t\t}\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-3-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:4:#ifndef __MT7925_MCU_H\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:5:#define __MT7925_MCU_H\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-6-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h=14=struct mt7925_mcu_eeprom_info {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-16-\t__le32 valid;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:17:\tu8 data[MT7925_EEPROM_BLOCK_SIZE];\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-18-} __packed;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h=99=enum {\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:100:\tMT7925_TM_NORMAL,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:101:\tMT7925_TM_TESTMODE,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:102:\tMT7925_TM_ICAP,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:103:\tMT7925_TM_ICAP_OVERLAP,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:104:\tMT7925_TM_WIFISPECTRUM,\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-105-};\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h=217=enum {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-221-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:222:#define MT7925_RNR_SCAN_MAX_BSSIDS\t10\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-223-struct scan_hdr_tlv {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h=252=struct scan_ssid_tlv {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-263-\tu8 pad;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:264:\tstruct mt76_connac_mcu_scan_ssid ssids[MT7925_RNR_SCAN_MAX_BSSIDS];\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-265-} __packed;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h=512=struct bss_rlm_tlv {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-526-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:527:#define MT7925_STA_UPDATE_MAX_SIZE\t(sizeof(struct sta_req_hdr) +\t\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-528-\t\t\t\t\t sizeof(struct sta_rec_basic) +\t\t\\\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-547-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:548:#define MT7925_BSS_UPDATE_MAX_SIZE\t(sizeof(struct bss_req_hdr) +\t\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-549-\t\t\t\t\t sizeof(struct mt76_connac_bss_basic_tlv) +\t\\\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h=596=struct mt7925_wow_pattern_tlv {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-610-\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h:611:#define MT7925_WOW_PATTERN_TLV_V2_SIZE\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.h-612-\t(offsetof(struct mt7925_wow_pattern_tlv, rsv) + 3)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-3-\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:4:#ifndef __MT7925_H\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:5:#define __MT7925_H\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-6-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-9-\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:10:#define MT7925_BEACON_RATES_TBL\t\t25\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-11-\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:12:#define MT7925_TX_RING_SIZE\t\t2048\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:13:#define MT7925_TX_MCU_RING_SIZE\t\t256\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:14:#define MT7925_TX_FWDL_RING_SIZE\t128\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-15-\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:16:#define MT7925_RX_RING_SIZE\t\t1536\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:17:#define MT7925_RX_MCU_RING_SIZE\t\t512\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-18-#define MT7928_RX_MCU_WA_RING_SIZE\t512\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-19-\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:20:#define MT7925_EEPROM_SIZE\t\t3584\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:21:#define MT7925_TOKEN_SIZE\t\t8192\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-22-\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:23:#define MT7925_EEPROM_BLOCK_SIZE\t16\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-24-\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:25:#define MT7925_SKU_RATE_NUM\t\t161\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:26:#define MT7925_SKU_MAX_DELTA_IDX\tMT7925_SKU_RATE_NUM\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:27:#define MT7925_SKU_TABLE_SIZE\t\t(MT7925_SKU_RATE_NUM + 1)\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-28-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=58=enum mt7925_roc_req {\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:59:\tMT7925_ROC_REQ_JOIN,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:60:\tMT7925_ROC_REQ_ROC,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:61:\tMT7925_ROC_REQ_SUB_LINK,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:62:\tMT7925_ROC_REQ_MLSR_AG = 10,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:63:\tMT7925_ROC_REQ_MLSR_AA,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:64:\tMT7925_ROC_REQ_NUM\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-65-};\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=116=enum mt7925_txq_id {\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:117:\tMT7925_TXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:118:\tMT7925_TXQ_BAND1,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:119:\tMT7925_TXQ_MCU_WM = 15,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:120:\tMT7925_TXQ_FWDL,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-121-};\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=123=enum mt7925_rxq_id {\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:124:\tMT7925_RXQ_BAND0 = 2,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:125:\tMT7925_RXQ_BAND1,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:126:\tMT7925_RXQ_MCU_WM = 0,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:127:\tMT7925_RXQ_MCU_WM2, /* for tx done */\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-128-};\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=130=enum mt7927_txq_id {\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:131:\tMT7927_TXQ_BAND0 = MT7925_TXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:132:\tMT7927_TXQ_BAND1 = MT7925_TXQ_BAND1,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:133:\tMT7927_TXQ_MCU_WM = MT7925_TXQ_MCU_WM,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:134:\tMT7927_TXQ_FWDL = MT7925_TXQ_FWDL,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-135-};\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h=161=enum {\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:162:\tMT7925_CLC_POWER,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:163:\tMT7925_CLC_CHAN,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h:164:\tMT7925_CLC_MAX_NUM,\ndrivers/net/wireless/mediatek/mt76/mt7925/mt7925.h-165-};\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=360=int mt7925_nan_change_configure(struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-371-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:372:\tskb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_CONF_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-373-\tif (!skb)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=645=void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-661-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:662:\tskb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_AVAIL_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-663-\tif (!skb)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c=865=int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-880-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c:881:\tskb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE);\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.c-882-\tif (!skb)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-3-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h:4:#ifndef __MT7925_NAN_H\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h:5:#define __MT7925_NAN_H\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-6-\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-30-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h:31:#define MT7925_NAN_CONF_MAX_SIZE\t\t\t\t\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-32-\t(sizeof(struct mt7925_nan_common_hdr) +\t\t\t\t\\\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-37-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h:38:#define MT7925_NAN_AVAIL_MAX_SIZE\t\t\t\t\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-39-\t(sizeof(struct mt7925_nan_common_hdr) +\t\t\t\t\\\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-42-\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h:43:#define MT7925_NAN_PEER_MAX_SIZE\t\t\t\t\t\\\ndrivers/net/wireless/mediatek/mt76/mt7925/nan.h-44-\t(sizeof(struct mt7925_nan_common_hdr) +\t\t\t\t\\\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=14=static const struct pci_device_id mt7925_pci_device_table[] = {\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-15-\t{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7925),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:16:\t\t.driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM },\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-17-\t{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0717),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:18:\t\t.driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM },\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-19-\t{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7927),\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=319=static const struct mt792x_dma_layout mt7925_dma_layout = {\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:320:\t.tx_data0 = mt792x_dma_ring(MT7925_TXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:321:\t\t\t\t MT7925_TX_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-322-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:323:\t.tx_mcu = mt792x_dma_ring(MT7925_TXQ_MCU_WM,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:324:\t\t\t\t MT7925_TX_MCU_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-325-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:326:\t.tx_fwdl = mt792x_dma_ring(MT7925_TXQ_FWDL,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:327:\t\t\t\t MT7925_TX_FWDL_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-328-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:329:\t.rx_mcu = mt792x_dma_ring(MT7925_RXQ_MCU_WM,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:330:\t\t\t\t MT7925_RX_MCU_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-331-\t\t\t\t MT_RX_EVENT_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:332:\t.rx_data = mt792x_dma_ring(MT7925_RXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:333:\t\t\t\t MT7925_RX_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-334-\t\t\t\t MT_RX_DATA_RING_BASE),\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=337=static const struct mt792x_dma_layout mt7927_dma_layout = {\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-338-\t.tx_data0 = mt792x_dma_ring(MT7927_TXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:339:\t\t\t\t MT7925_TX_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-340-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-341-\t.tx_mcu = mt792x_dma_ring(MT7927_TXQ_MCU_WM,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:342:\t\t\t\t MT7925_TX_MCU_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-343-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-344-\t.tx_fwdl = mt792x_dma_ring(MT7927_TXQ_FWDL,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:345:\t\t\t\t MT7925_TX_FWDL_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-346-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-347-\t.rx_mcu = mt792x_dma_ring(MT7927_RXQ_MCU_WM,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:348:\t\t\t\t MT7925_RX_MCU_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-349-\t\t\t\t MT_RX_EVENT_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-350-\t.rx_data = mt792x_dma_ring(MT7927_RXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:351:\t\t\t\t MT7925_RX_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-352-\t\t\t\t MT_RX_DATA_RING_BASE),\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=355=static const struct mt792x_dma_layout mt7928_dma_layout = {\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:356:\t.tx_data0 = mt792x_dma_ring(MT7925_TXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:357:\t\t\t\t MT7925_TX_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-358-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:359:\t.tx_mcu = mt792x_dma_ring(MT7925_TXQ_MCU_WM,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:360:\t\t\t\t MT7925_TX_MCU_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-361-\t\t\t\t MT_TX_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:362:\t.tx_fwdl = mt792x_dma_ring(MT7925_TXQ_FWDL,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:363:\t\t\t\t MT7925_TX_FWDL_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-364-\t\t\t\t MT_TX_RING_BASE),\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-368-\t.rx_mcu = mt792x_dma_ring(MT7928_RXQ_MCU_WM,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:369:\t\t\t\t MT7925_RX_MCU_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-370-\t\t\t\t MT_RX_EVENT_RING_BASE),\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-371-\t.rx_data = mt792x_dma_ring(MT7928_RXQ_BAND0,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:372:\t\t\t\t MT7925_RX_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-373-\t\t\t\t MT_RX_DATA_RING_BASE),\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=376=static int mt7927_dma_init(struct mt792x_dev *dev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-385-\t\t\t MT7927_RXQ_DATA2,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:386:\t\t\t MT7925_RX_MCU_RING_SIZE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-387-\t\t\t MT_RX_BUF_SIZE,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c=476=static const struct mt792x_pcie_reg mt7925_pcie_reg = {\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:477:\t.imask = MT7925_PCIE_MAC_INT_ENABLE,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c:478:\t.pm = MT7925_PCIE_MAC_PM,\ndrivers/net/wireless/mediatek/mt76/mt7925/pci.c-479-};\n\n"
} |
| 41/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 72278 output: 47 thoughts: 45 Thoughts: Okay, let's dive into this. Here's how I'd approach this task. **Investigating MT7925 & MT76 Wireless Configuration** Alright, I need to get a handle on the configuration options for these Mediatek wireless drivers. My first step is to locate and examine the `Kconfig` files. I'm going to start by checking `drivers/net/wireless/mediatek/mt76/mt7925/Kconfig` and `drivers/net/wireless/mediatek/mt76/Kconfig`. Those should give me a good overview of what's configurable at the 7925 level and the broader 76 platform. I expect to find dependencies, default values, and potentially some module-specific settings that I'll need to understand to work with these drivers. I'm looking for the core options and any nuances that might affect my configuration decisions later on. |
| 42/2 | 2026/08/31 03:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/mt7925/Kconfig",
"FirstLine": 1,
"LineCount": 40
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: BSD-3-Clause-Clear\n 2:\tconfig MT7925_COMMON\n 3:\t\ttristate\n 4:\t\tselect MT792x_LIB\n 5:\t\tselect WANT_DEV_COREDUMP\n 6:\t\n 7:\tconfig MT7925E\n 8:\t\ttristate \"MediaTek MT7925E (PCIe) support\"\n 9:\t\tselect MT7925_COMMON\n 10:\t\tdepends on MAC80211\n 11:\t\tdepends on PCI\n 12:\t\thelp\n 13:\t\t This adds support for MT7925-based wireless PCIe devices,\n 14:\t\t which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be\n 15:\t\t 2x2:2SS 4096-QAM, 160MHz channels.\n 16:\t\n 17:\t\t To compile this driver as a module, choose M here.\n 18:\t\n 19:\tconfig MT7925U\n 20:\t\ttristate \"MediaTek MT7925U (USB) support\"\n 21:\t\tselect MT792x_USB\n 22:\t\tselect MT7925_COMMON\n 23:\t\tdepends on MAC80211\n 24:\t\tdepends on USB\n 25:\t\thelp\n 26:\t\t This adds support for MT7925-based wireless USB devices,\n 27:\t\t which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be\n 28:\t\t 2x2:2SS 4096-QAM, 160MHz channels.\n 29:\t\n 30:\t\t To compile this driver as a module, choose M here.\n"
} |
| 43/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 73051 output: 41 thoughts: 24 Thoughts: Here's my take: **Investigating the Kconfig File for MT76 Wireless Drivers** Okay, so we're looking at some wireless driver configurations, and my gut feeling is that we're missing something crucial. I've been down this road before. To make sure we've got the whole picture, I need to take a look at the `drivers/net/wireless/mediatek/mt76/Kconfig` file. It's often the central source of truth for these types of configurations. I know the Mediatek MT76 drivers pretty well, and based on past experience, Kconfig files are the best starting point when I encounter a system that is not behaving as expected. Let's see what's being enabled or disabled there and whether there's a setting that's causing this issue. Time to dig in. |
| 44/2 | 2026/08/31 03:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/Kconfig",
"FirstLine": 1,
"LineCount": 50
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: BSD-3-Clause-Clear\n 2:\tconfig MT76_CORE\n 3:\t\ttristate\n 4:\t\tselect PAGE_POOL\n 5:\t\n 6:\tconfig MT76_LEDS\n 7:\t\tbool\n 8:\t\tdepends on MT76_CORE\n 9:\t\tdepends on LEDS_CLASS=y || MT76_CORE=LEDS_CLASS\n 10:\t\tdefault y\n 11:\t\n 12:\tconfig MT76_USB\n 13:\t\ttristate\n 14:\t\tdepends on MT76_CORE\n 15:\t\n 16:\tconfig MT76_SDIO\n 17:\t\ttristate\n 18:\t\tdepends on MT76_CORE\n 19:\t\n 20:\tconfig MT76x02_LIB\n 21:\t\ttristate\n 22:\t\tselect MT76_CORE\n 23:\t\n 24:\tconfig MT76x02_USB\n 25:\t\ttristate\n 26:\t\tselect MT76_USB\n 27:\t\n 28:\tconfig MT76_CONNAC_LIB\n 29:\t\ttristate\n 30:\t\tselect MT76_CORE\n 31:\t\n 32:\tconfig MT792x_LIB\n 33:\t\ttristate\n 34:\t\tselect MT76_CONNAC_LIB\n 35:\t\n 36:\tconfig MT792x_USB\n 37:\t\ttristate\n 38:\t\tselect MT76_USB\n 39:\t\n 40:\tconfig MT76_NPU\n 41:\t\ttristate\n 42:\t\tdepends on NET_AIROHA_NPU=y || MT76_CORE=NET_AIROHA_NPU\n 43:\t\n 44:\tsource \"drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig\"\n 45:\tsource \"drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig\"\n 46:\tsource \"drivers/net/wireless/mediatek/mt76/mt7603/Kconfig\"\n 47:\tsource \"drivers/net/wireless/mediatek/mt76/mt7615/Kconfig\"\n 48:\tsource \"drivers/net/wireless/mediatek/mt76/mt7915/Kconfig\"\n 49:\tsource \"drivers/net/wireless/mediatek/mt76/mt7921/Kconfig\"\n 50:\tsource \"drivers/net/wireless/mediatek/mt76/mt7996/Kconfig\"\n"
} |
| 45/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 73993 output: 42 thoughts: 94 Thoughts: **Investigating the mt7925 Driver Configuration** Okay, let's dig into this. I need to understand how the mt7925 driver is configured within the larger Mediatek wireless framework. My first hunch is that the `Kconfig` files are the key. Specifically, the path I'm assuming is the place to look first `drivers/net/wireless/mediatek/mt76/Kconfig`. Line 51 and onward is where I'd expect the inclusion of the mt7925-specific Kconfig. It's likely `source "drivers/net/wireless/mediatek/mt76/mt7925/Kconfig"`. To confirm this, I need to scan lines 50 to 60 within `drivers/net/wireless/mediatek/mt76/Kconfig`. That should give me the context I need. |
| 46/2 | 2026/08/31 03:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/mt76/Kconfig",
"FirstLine": 50,
"LineCount": 15
}Results: {
"Contents": " 50:\tsource \"drivers/net/wireless/mediatek/mt76/mt7996/Kconfig\"\n 51:\tsource \"drivers/net/wireless/mediatek/mt76/mt7925/Kconfig\"\n"
} |
| 47/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 74393 output: 29 thoughts: 21 Thoughts: Here's my take on those thoughts: **Analyzing the Mediatek Wireless Driver Kconfig** Okay, so I need to dive into the `drivers/net/wireless/mediatek/Kconfig` file. I'm assuming there's a specific configuration option or dependency I need to understand better. First, I need to check the *parent* Kconfig file for that driver. That's likely where the higher-level architecture of this driver is defined, and where the broader system-level dependencies are laid out. Understanding the parent's context is *crucial* before I even think about touching the Mediatek-specific configurations. It’s the architectural roadmap, and I need to see the bigger picture before getting into the weeds of the specifics. This parent will likely guide how the Mediatek driver is integrated and how it interacts with other wireless or networking components. Let's see what the parent says... |
| 48/2 | 2026/08/31 03:57 | tool | grepper |
0mArgs:{
"Expression": "source.*mediatek",
"PathPrefix": "drivers/net/wireless"
}Results: {
"Output": "drivers/net/wireless/Kconfig=27=source \"drivers/net/wireless/marvell/Kconfig\"\ndrivers/net/wireless/Kconfig:28:source \"drivers/net/wireless/mediatek/Kconfig\"\ndrivers/net/wireless/Kconfig-29-source \"drivers/net/wireless/microchip/Kconfig\"\n--\ndrivers/net/wireless/mediatek/Kconfig=13=if WLAN_VENDOR_MEDIATEK\ndrivers/net/wireless/mediatek/Kconfig:14:source \"drivers/net/wireless/mediatek/mt7601u/Kconfig\"\ndrivers/net/wireless/mediatek/Kconfig:15:source \"drivers/net/wireless/mediatek/mt76/Kconfig\"\ndrivers/net/wireless/mediatek/Kconfig-16-endif # WLAN_VENDOR_MEDIATEK\n--\ndrivers/net/wireless/mediatek/mt76/Kconfig=40=config MT76_NPU\n--\ndrivers/net/wireless/mediatek/mt76/Kconfig-43-\ndrivers/net/wireless/mediatek/mt76/Kconfig:44:source \"drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig\"\ndrivers/net/wireless/mediatek/mt76/Kconfig:45:source \"drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig\"\ndrivers/net/wireless/mediatek/mt76/Kconfig:46:source \"drivers/net/wireless/mediatek/mt76/mt7603/Kconfig\"\ndrivers/net/wireless/mediatek/mt76/Kconfig:47:source \"drivers/net/wireless/mediatek/mt76/mt7615/Kconfig\"\ndrivers/net/wireless/mediatek/mt76/Kconfig:48:source \"drivers/net/wireless/mediatek/mt76/mt7915/Kconfig\"\ndrivers/net/wireless/mediatek/mt76/Kconfig:49:source \"drivers/net/wireless/mediatek/mt76/mt7921/Kconfig\"\ndrivers/net/wireless/mediatek/mt76/Kconfig:50:source \"drivers/net/wireless/mediatek/mt76/mt7996/Kconfig\"\ndrivers/net/wireless/mediatek/mt76/Kconfig:51:source \"drivers/net/wireless/mediatek/mt76/mt7925/Kconfig\"\n"
} |
| 49/2 | 2026/08/31 03:57 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 75254 output: 37 thoughts: 17 Thoughts: Here's my take on those thoughts, tailored for an expert audience: **Diving into the Mediatek Wireless Configuration** Okay, time to get my hands dirty. I need to take a look at the configuration for Mediatek wireless drivers. My first port of call will be `drivers/net/wireless/mediatek/Kconfig`. This file *should* be the central hub for all the build-time options and dependencies related to Mediatek's wireless silicon. I expect to find the usual suspects: options for various Mediatek chipsets and variants, dependencies on other kernel features (like regulatory, MAC80211), and potentially some device-specific configurations. I'm hoping it's well-structured and uses the standard Kconfig conventions to avoid too much digging. I want to quickly understand which drivers are available, how they're enabled, and what supporting infrastructure is required. I need to get a clear picture of the build-time configuration options so I know what's possible, what's not, and what I might need to consider when configuring a system or troubleshooting a specific driver. |
| 50/2 | 2026/08/31 03:58 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/mediatek/Kconfig",
"FirstLine": 1,
"LineCount": 20
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\tconfig WLAN_VENDOR_MEDIATEK\n 3:\t\tbool \"MediaTek devices\"\n 4:\t\tdefault y\n 5:\t\thelp\n 6:\t\t If you have a wireless card belonging to this class, say Y.\n 7:\t\n 8:\t\t Note that the answer to this question doesn't directly affect the\n 9:\t\t kernel: saying N will just cause the configurator to skip all the\n 10:\t\t questions about these cards. If you say Y, you will be asked for\n 11:\t\t your specific card in the following questions.\n 12:\t\n 13:\tif WLAN_VENDOR_MEDIATEK\n 14:\tsource \"drivers/net/wireless/mediatek/mt7601u/Kconfig\"\n 15:\tsource \"drivers/net/wireless/mediatek/mt76/Kconfig\"\n 16:\tendif # WLAN_VENDOR_MEDIATEK\n"
} |
| 51/2 | 2026/08/31 03:58 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 75799 output: 34 thoughts: 14 Thoughts: Here's my summary, as though I'm thinking it: **Kconfig Dive Begins** Alright, time to get to work. Let's start digging into the Wi-Fi driver configuration. My instinct says the central configuration options will be located within the `drivers/net/wireless/Kconfig` file. That's the typical location for core Wi-Fi driver feature flags and dependencies. It’s the starting point for understanding how the kernel's wireless subsystem is built and configured. I'll need to understand the structure within this file. I expect to find dependencies on various hardware platforms, PHY types, regulatory domains, and probably some protocol-specific settings there. Time to see what we can find. |
| 52/2 | 2026/08/31 03:58 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/Kconfig",
"FirstLine": 1,
"LineCount": 35
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t#\n 3:\t# Wireless LAN device configuration\n 4:\t#\n 5:\t\n 6:\tmenuconfig WLAN\n 7:\t\tbool \"Wireless LAN\"\n 8:\t\tdepends on !S390\n 9:\t\tdepends on NET\n 10:\t\tselect WIRELESS\n 11:\t\tdefault y\n 12:\t\thelp\n 13:\t\t This section contains all the pre 802.11 and 802.11 wireless\n 14:\t\t device drivers. For a complete list of drivers and documentation\n 15:\t\t on them refer to the wireless wiki:\n 16:\t\n 17:\t\t https://wireless.wiki.kernel.org/en/users/Drivers\n 18:\t\n 19:\tif WLAN\n 20:\t\n 21:\tsource \"drivers/net/wireless/admtek/Kconfig\"\n 22:\tsource \"drivers/net/wireless/ath/Kconfig\"\n 23:\tsource \"drivers/net/wireless/atmel/Kconfig\"\n 24:\tsource \"drivers/net/wireless/broadcom/Kconfig\"\n 25:\tsource \"drivers/net/wireless/intel/Kconfig\"\n 26:\tsource \"drivers/net/wireless/intersil/Kconfig\"\n 27:\tsource \"drivers/net/wireless/marvell/Kconfig\"\n 28:\tsource \"drivers/net/wireless/mediatek/Kconfig\"\n 29:\tsource \"drivers/net/wireless/microchip/Kconfig\"\n 30:\tsource \"drivers/net/wireless/morsemicro/Kconfig\"\n 31:\tsource \"drivers/net/wireless/nxp/Kconfig\"\n 32:\tsource \"drivers/net/wireless/purelifi/Kconfig\"\n 33:\tsource \"drivers/net/wireless/ralink/Kconfig\"\n 34:\tsource \"drivers/net/wireless/realtek/Kconfig\"\n 35:\tsource \"drivers/net/wireless/rsi/Kconfig\"\n"
} |
| 53/2 | 2026/08/31 03:58 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 76527 output: 296 thoughts: 1622 Thoughts: **Analysis of the MT7925 Driver for Fuzzing**
Okay, so here's the breakdown of what I'm thinking. We need to figure out if this patch is worth fuzzing, and if so, how to best target it. My initial thought is we need to analyze what configurations are needed to run the MT7925 driver. I've identified the following: `WLAN`, `WLAN_VENDOR_MEDIATEK`, `MAC80211`, `MT76_CORE`, `MT76_CONNAC_LIB`, `MT792x_LIB`, `MT7925_COMMON`, `MT7925E` (for PCI devices), and `MT7925U` (for USB devices). `MT792x_USB`, `USB`, and `PCI` are selected based on the specific MT7925 variant.
Now, does this patch actually introduce functionality worth fuzzing? Let's see... it adds `mt7925/stats.c` containing various MCU interaction functions and TLV parsing: `mt792x_mcu_get_stat`, `mt7925_mcu_get_mib_info`, `mt7925_mcu_get_link_quality`, `mt792x_mcu_get_wtbl_rate`, `mt7925_print_last_tx_rate`, and some rate computation helpers. There are also changes to `debugfs.c`, adding `mt7925_dump_auto_rate_table` and `mt792x_stats` (a seq_file). It looks like the added functions are all part of the driver logic and can be reached via debugfs - `/sys/kernel/debug/.../stats`.
Are any of these functions *hot* functions? No, these seem to be MCU query helpers and debugfs formatting helpers, not core packet handling.
Since we are adding debugfs entries, we should definitely set `WorthFuzzing=true`.
For the fuzzing targets (FocusSymbols) what non-static API functions are added here? Here's the list of non-static and distinct API functions added by the patch: `mt792x_stats` (debugfs handler), `mt7925_mcu_get_mib_info`, `mt792x_mcu_get_stat`, `mt792x_mcu_get_wtbl_rate`, `mt7925_mcu_get_link_quality`, `mt7925_print_last_tx_rate`, `mt7925_dump_auto_rate_table`, `mt7925_get_ap_sta_rec_idx`, `mt7925_wtbl_get_sgi`, `mt7925_wtbl_get_ldpc`, and `mt7925_hw_rate_ofdm_str`.
I've got to double-check which of these are static vs. non-static and the exact names: `mt792x_stats` is a seqfile entrypoint and is static, `mt7925_dump_auto_rate_table` is static, the rest are non-static.
We also have to double-check the configs. I already listed those that are required in the analysis above. Specifically, `WLAN`, `WLAN_VENDOR_MEDIATEK`, `MAC80211`, `MT7925_COMMON`, `MT7925E`, and `MT7925U`. A quick sanity check reveals `WLAN` is menuconfig, `WLAN_VENDOR_MEDIATEK` is a bool, `MAC80211` is a dependency, and the other options select `MT7925_COMMON` which, in turn, selects `MT792x_LIB`. We will need `DEBUG_FS` enabled for debugfs to be available.
So, let me summarize:
* **WorthFuzzing**: `true`
* **FocusSymbols**:
* `mt792x_stats`
* `mt792x_mcu_get_stat`
* `mt7925_mcu_get_mib_info`
* `mt7925_mcu_get_link_quality`
* `mt792x_mcu_get_wtbl_rate`
* `mt7925_print_last_tx_rate`
* `
|
| 54/2 | 2026/08/31 03:58 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"WLAN",
"WLAN_VENDOR_MEDIATEK",
"MAC80211",
"MT7925E",
"MT7925U",
"MT7925_COMMON",
"DEBUG_FS"
],
"FocusSymbols": [
"mt792x_stats",
"mt792x_mcu_get_stat",
"mt7925_mcu_get_mib_info",
"mt7925_mcu_get_link_quality",
"mt792x_mcu_get_wtbl_rate",
"mt7925_print_last_tx_rate",
"mt7925_get_ap_sta_rec_idx",
"mt7925_wtbl_get_sgi",
"mt7925_wtbl_get_ldpc"
],
"Reasoning": "The patch adds debugfs statistics support and associated MCU querying and TLV parsing logic (STA stats, MIB counters, link quality, WTBL auto-rate table, TX vector decode) for MediaTek MT7925 devices. These code paths contain parsing and formatting logic reachable via debugfs and USB device emulation.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"WLAN",
"WLAN_VENDOR_MEDIATEK",
"MAC80211",
"MT7925E",
"MT7925U",
"MT7925_COMMON",
"DEBUG_FS"
],
"FocusSymbols": [
"mt792x_stats",
"mt792x_mcu_get_stat",
"mt7925_mcu_get_mib_info",
"mt7925_mcu_get_link_quality",
"mt792x_mcu_get_wtbl_rate",
"mt7925_print_last_tx_rate",
"mt7925_get_ap_sta_rec_idx",
"mt7925_wtbl_get_sgi",
"mt7925_wtbl_get_ldpc"
],
"Reasoning": "The patch adds debugfs statistics support and associated MCU querying and TLV parsing logic (STA stats, MIB counters, link quality, WTBL auto-rate table, TX vector decode) for MediaTek MT7925 devices. These code paths contain parsing and formatting logic reachable via debugfs and USB device emulation.",
"WorthFuzzing": true
} |
| 55/1 | 2026/08/31 03:58 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 56/2 | 2026/08/31 03:58 | agent | kmsan-evaluator |
0mModel:core Args: null Results: {
"KMSANReasoning": "The patch adds debugfs statistics reporting and MCU query helpers for the mt7925 driver (including station statistics, MIB counters, link quality, and auto-rate table dumping).\n\nEvaluation of KMSAN vs KASAN applicability:\n1. Memory Initialization:\n - Heap allocations use kzalloc() (e.g., stats buffer and MIB request buffer).\n - Stack request structures (mt7925_sta_stats_req, mt7925_wtbl_rate_req, mt7925_lq_req) are initialized using C designated initializers, ensuring all omitted fields and padding are zeroed.\n - Stack arrays such as mib_values are explicitly zeroed via memset() at the entry of mt7925_mcu_get_mib_info().\n - Stack struct wtbl_rate is only read if mt792x_mcu_get_wtbl_rate() returns 0 (which copies the full struct from firmware response skb), guarded by the boolean flag wtbl_rate_valid.\n2. User-Space Exposure:\n - Output to user space is handled exclusively through seq_printf/seq_puts via debugfs seq_file entries (converting data to formatted ASCII strings). There are no raw binary structure copies or memory leaks to user space (no copy_to_user or raw netlink/ioctl transfers).\n3. Any potential bugs related to MCU skb parsing or array indices are bounds/memory corruption issues covered by standard KASAN.\n\nBecause no uninitialized memory reads or info-leaks are introduced, a dedicated KMSAN session is not required.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
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 d28e1a6c65afcbfa8b3c17b2f361b8ed61e44efc
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 31 03:56:29 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 0ededa569e9a5..bf0f105c786e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1483,6 +1483,179 @@ enum {
MT_NIC_CAP_EML_CAP = 0x22,
};
+enum {
+ UNI_CMD_ID_STATISTICS_BASIC = 0,
+ UNI_CMD_ID_STATISTICS_LINK_QUALITY = 1,
+ UNI_CMD_ID_STATISTICS_STA = 2,
+ UNI_CMD_ID_STATISTICS_BUG_REPORT = 3,
+ UNI_CMD_ID_STATISTICS_TX_STATS = 4,
+ UNI_CMD_ID_STATISTICS_ALL_STATS = 5,
+ UNI_CMD_ID_STATISTICS_EML_STATS = 6,
+ UNI_CMD_ID_STATISTICS_REGULAR_STATS = 7,
+ UNI_CMD_ID_STATISTICS_BSS_LINK_QUALITY = 8,
+ UNI_CMD_ID_STATISTICS_ML_CHNL_COND = 9,
+ UNI_CMD_ID_STATISTICS_WTBL = 10,
+ UNI_CMD_ID_STATISTICS_LINK_LAYER_STATS = 128,
+ UNI_CMD_ID_STATISTICS_PPDU_LATENCY = 129,
+ UNI_CMD_ID_STATISTICS_CURRENT_TX_RATE = 130,
+ UNI_CMD_ID_STATISTICS_SET_TX_BITRATE_MONITOR = 131,
+ UNI_CMD_ID_STATISTICS_GET_PREDICT_TX_BITRATE = 132,
+ UNI_CMD_ID_STATISTICS_SET_ATPS_TYPE_RATE_MODE = 133,
+ UNI_CMD_ID_STATISTICS_SET_BEACON_REPORT = 134,
+ UNI_CMD_ID_STATISTICS_BSS_CURRENT_TX_RATE = 135,
+ UNI_CMD_ID_STATISTICS_GET_BSS_PREDICT_TX_BITRATE = 136,
+ UNI_CMD_ID_STATISTICS_MAX_NUM
+};
+
+enum mt7925_mib_counter {
+ UNI_CMD_MIB_CNT_RX_FCS_ERR = 0,
+ UNI_CMD_MIB_CNT_RX_FIFO_OVERFLOW = 1,
+ UNI_CMD_MIB_CNT_RX_MPDU = 2,
+ UNI_CMD_MIB_CNT_AMPDU_RX_COUNT = 3,
+ UNI_CMD_MIB_CNT_RX_TOTAL_BYTE = 4,
+ UNI_CMD_MIB_CNT_RX_VALID_AMPDU_SF = 5,
+ UNI_CMD_MIB_CNT_RX_VALID_BYTE = 6,
+ UNI_CMD_MIB_CNT_CHANNEL_IDLE = 7,
+ UNI_CMD_MIB_CNT_VEC_DROP = 8,
+ UNI_CMD_MIB_CNT_DELIMITER_FAIL = 9,
+ UNI_CMD_MIB_CNT_VEC_MISMATCH = 10,
+ UNI_CMD_MIB_CNT_MDRDY = 11,
+ UNI_CMD_MIB_CNT_RX_CCK_MDRDY_TIME = 12,
+ UNI_CMD_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME = 13,
+ UNI_CMD_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME = 14,
+ UNI_CMD_MIB_CNT_PF_DROP = 15,
+ UNI_CMD_MIB_CNT_LEN_MISMATCH = 16,
+ UNI_CMD_MIB_CNT_P_CCA_TIME = 17,
+ UNI_CMD_MIB_CNT_S_CCA_TIME = 18,
+ UNI_CMD_MIB_CNT_CCA_NAV_TX_TIME = 19,
+ UNI_CMD_MIB_CNT_P_ED_TIME = 20,
+ UNI_CMD_MIB_CNT_BCN_TX = 21,
+ UNI_CMD_MIB_CNT_TX_BW_20MHZ = 22,
+ UNI_CMD_MIB_CNT_TX_BW_40MHZ = 23,
+ UNI_CMD_MIB_CNT_TX_BW_80MHZ = 24,
+ UNI_CMD_MIB_CNT_TX_BW_160MHZ = 25,
+ UNI_CMD_RMAC_CNT_OBSS_AIRTIME = 26,
+ UNI_CMD_RMAC_CNT_NONWIFI_AIRTIME = 27,
+ UNI_CMD_MIB_CNT_TX_DUR_CNT = 28,
+ UNI_CMD_MIB_CNT_RX_DUR_CNT = 29,
+ UNI_CMD_MIB_CNT_BA_CNT = 30,
+ UNI_CMD_MIB_CNT_MAC2PHY_TX_TIME = 31,
+ UNI_CMD_MIB_CNT_RX_OUT_OF_RANGE_COUNT = 32,
+ UNI_CMD_MIB_CNT_IBF_TX = 33,
+ UNI_CMD_MIB_CNT_EBF_TX = 34,
+ UNI_CMD_MIB_CNT_MUBF_TX = 35,
+ UNI_CMD_MIB_CNT_RX_BF_VHTFBK = 36,
+ UNI_CMD_MIB_CNT_RX_BF_HTFBK = 37,
+ UNI_CMD_MIB_CNT_RX_BF_HEFBK = 38,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_BFPOLL_TRI = 39,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_TRI = 40,
+ UNI_CMD_MIB_CNT_BFEE_RX_FBKCQI = 41,
+ UNI_CMD_MIB_CNT_BFEE_RX_NDP = 42,
+ UNI_CMD_MIB_CNT_RX_BF_IBF_UPT = 43,
+ UNI_CMD_MIB_CNT_RX_BF_EBF_UPT = 44,
+ UNI_CMD_MIB_CNT_BFEE_SP_ABORT = 45,
+ UNI_CMD_MIB_CNT_BFEE_TB_LEN_ERR = 46,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_MUTE = 47,
+ UNI_CMD_MIB_CNT_BFEE_TMAC_ABORT = 48,
+ UNI_CMD_MIB_CNT_BFEE_TXFBK_CPL = 49,
+ UNI_CMD_MIB_CNT_BFEE_COANT_BLKTX = 50,
+ UNI_CMD_MIB_CNT_BFEE_FBK_SEG = 51,
+ UNI_CMD_MIB_CNT_NAV_TIME = 52,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT1 = 53,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT0 = 54,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT3 = 55,
+ UNI_CMD_MIB_CNT_TX_ABORT_CNT2 = 56,
+ UNI_CMD_MIB_CNT_BSS0_RTS_TX_CNT = 57,
+ UNI_CMD_MIB_CNT_BSS1_RTS_TX_CNT = 58,
+ UNI_CMD_MIB_CNT_BSS2_RTS_TX_CNT = 59,
+ UNI_CMD_MIB_CNT_BSS3_RTS_TX_CNT = 60,
+ UNI_CMD_MIB_CNT_BSS0_RTS_RETRY = 61,
+ UNI_CMD_MIB_CNT_BSS1_RTS_RETRY = 62,
+ UNI_CMD_MIB_CNT_BSS2_RTS_RETRY = 63,
+ UNI_CMD_MIB_CNT_BSS3_RTS_RETRY = 64,
+ UNI_CMD_MIB_CNT_BSS0_BA_MISS = 65,
+ UNI_CMD_MIB_CNT_BSS1_BA_MISS = 66,
+ UNI_CMD_MIB_CNT_BSS2_BA_MISS = 67,
+ UNI_CMD_MIB_CNT_BSS3_BA_MISS = 68,
+ UNI_CMD_MIB_CNT_BSS0_ACK_FAIL = 69,
+ UNI_CMD_MIB_CNT_BSS1_ACK_FAIL = 70,
+ UNI_CMD_MIB_CNT_BSS2_ACK_FAIL = 71,
+ UNI_CMD_MIB_CNT_BSS3_ACK_FAIL = 72,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY = 73,
+ UNI_CMD_MIB_CNT_BSS1_FRAME_RETRY = 74,
+ UNI_CMD_MIB_CNT_BSS2_FRAME_RETRY = 75,
+ UNI_CMD_MIB_CNT_BSS3_FRAME_RETRY = 76,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_2 = 77,
+ UNI_CMD_MIB_CNT_BSS1_FRAME_RETRY_2 = 78,
+ UNI_CMD_MIB_CNT_BSS2_FRAME_RETRY_2 = 79,
+ UNI_CMD_MIB_CNT_BSS3_FRAME_RETRY_2 = 80,
+ UNI_CMD_MIB_CNT_RX_A1_SEARCH = 81,
+ UNI_CMD_MIB_CNT_RX_DROP_MPDU = 82,
+ UNI_CMD_MIB_CNT_RX_UNWANTED = 83,
+ UNI_CMD_MIB_CNT_RX_FCS_OK = 84,
+ UNI_CMD_MIB_CNT_SU_TX_OK = 85,
+ UNI_CMD_MIB_CNT_TX_FULL_BW = 86,
+ UNI_CMD_MIB_CNT_TX_AUTO_BW = 87,
+ UNI_CMD_MIB_CNT_CCA_SAMPLE_IDLE = 88,
+ UNI_CMD_MIB_CNT_CCA_SAMPLE_ACTIVE = 89,
+ UNI_CMD_MIB_CNT_CCA_TIME = 90,
+ UNI_CMD_MIB_CNT_S_20BW_CCA_TIME = 91,
+ UNI_CMD_MIB_CNT_S_40BW_CCA_TIME = 92,
+ UNI_CMD_MIB_CNT_S_80BW_CCA_TIME = 93,
+ UNI_CMD_MIB_CNT_S_160BW_CCA_TIME = 94,
+ UNI_CMD_MIB_CNT_S_P20BW_0_ED_TIME = 95,
+ UNI_CMD_MIB_CNT_S_P20BW_1_ED_TIME = 96,
+ UNI_CMD_MIB_CNT_S_P20BW_2_ED_TIME = 97,
+ UNI_CMD_MIB_CNT_S_P20BW_3_ED_TIME = 98,
+ UNI_CMD_MIB_CNT_S_P20BW_4_ED_TIME = 99,
+ UNI_CMD_MIB_CNT_S_P20BW_5_ED_TIME = 100,
+ UNI_CMD_MIB_CNT_S_P20BW_6_ED_TIME = 101,
+ UNI_CMD_MIB_CNT_S_P20BW_7_ED_TIME = 102,
+ UNI_CMD_MIB_CNT_S_P20BW_8_ED_TIME = 103,
+ UNI_CMD_MIB_CNT_S_P20BW_9_ED_TIME = 104,
+ UNI_CMD_MIB_CNT_S_P20BW_10_ED_TIME = 105,
+ UNI_CMD_MIB_CNT_S_P20BW_11_ED_TIME = 106,
+ UNI_CMD_MIB_CNT_S_P20BW_12_ED_TIME = 107,
+ UNI_CMD_MIB_CNT_S_P20BW_13_ED_TIME = 108,
+ UNI_CMD_MIB_CNT_S_P20BW_14_ED_TIME = 109,
+ UNI_CMD_MIB_CNT_S_P20BW_15_ED_TIME = 110,
+ UNI_CMD_MIB_CNT_TX_BW_320MHZ = 111,
+ UNI_CMD_MIB_CNT_TX_DDLMT_RNG0 = 112, /* Rng0~Rng4 112~116 */
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_3 = 117, /* 117~120 */
+ UNI_CMD_MIB_CNT_BSS0_TX = 121, /* 121~124 */
+ UNI_CMD_MIB_CNT_BSS0_TX_DATA = 125, /* 125~128 */
+ UNI_CMD_MIB_CNT_BSS0_TX_BYTE = 129, /* 129~132 */
+ UNI_CMD_MIB_CNT_RX_OK_BSS0 = 133, /* 133~136 */
+ UNI_CMD_MIB_CNT_RX_BYTE_BSS0 = 137, /* 137~140 */
+ UNI_CMD_MIB_CNT_RX_DATA_BSS0 = 141, /* 141~144 */
+ UNI_CMD_MIB_CNT_MBSS0_TX_OK = 145, /* 145~160 */
+ UNI_CMD_MIB_CNT_MBSS0_TX_BYTE = 161, /* 161~176 */
+ UNI_CMD_MIB_CNT_RX_OK_MBSS0 = 177, /* 177~192 */
+ UNI_CMD_MIB_CNT_RX_BYTE_MBSS0 = 193, /* 193~208 */
+ UNI_CMD_MIB_CNT_AMPDU = 209,
+ UNI_CMD_MIB_CNT_AMPDU_MPDU = 210,
+ UNI_CMD_MIB_CNT_AMPDU_ACKED = 211,
+ UNI_CMD_MIB_CNT_MAX_NUM
+};
+
+enum ENUM_UNI_CMD_GET_STATISTICS_TAG {
+ UNI_CMD_GET_STATISTICS_TAG_BASIC = 0,
+ UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1,
+ UNI_CMD_GET_STATISTICS_TAG_STA = 2,
+ UNI_CMD_GET_STATISTICS_TAG_BUG_REPORT = 3,
+ UNI_CMD_GET_STATISTICS_TAG_EML_STATS = 6,
+ UNI_CMD_GET_STATISTICS_TAG_REGULAR_STATS = 7,
+ UNI_CMD_GET_STATISTICS_TAG_BSS_LINK_QUALITY = 8,
+ UNI_CMD_GET_STATISTICS_TAG_GET_ML_CHNL_COND = 9,
+ UNI_CMD_GET_STATISTICS_TAG_STAT_WTBL = 10,
+ UNI_CMD_GET_STATISTICS_TAG_LINK_LAYER_STATS = 0x80,
+ UNI_CMD_GET_STATISTICS_TAG_PPDU_LATENCY,
+ UNI_CMD_GET_STATISTICS_TAG_CURRENT_TX_RATE,
+ UNI_CMD_GET_STATISTICS_TAG_BEACON_REPORT = 0x86,
+ UNI_CMD_GET_STATISTICS_TAG_BSS_CURRENT_TX_RATE = 0x87,
+ UNI_CMD_GET_STATISTICS_TAG_BSS_PRED_TX_BITRATE = 0x88,
+};
+
#define UNI_WOW_DETECT_TYPE_MAGIC BIT(0)
#define UNI_WOW_DETECT_TYPE_ANY BIT(1)
#define UNI_WOW_DETECT_TYPE_DISCONNECT BIT(2)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile
index f9dcc0bba393c..3863a89b89742 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_MT7925_COMMON) += mt7925-common.o
obj-$(CONFIG_MT7925E) += mt7925e.o
obj-$(CONFIG_MT7925U) += mt7925u.o
-mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o
+mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o stats.o
mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7925e-y := pci.o pci_mac.o pci_mcu.o
mt7925u-y := usb.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
index d01ff49de47af..ace501049792e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
@@ -1,8 +1,11 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/* Copyright (C) 2023 MediaTek Inc. */
+#include <linux/math64.h>
+
#include "mt7925.h"
#include "mcu.h"
+#include "stats.h"
static int
mt7925_reg_set(void *data, u64 val)
@@ -286,6 +289,366 @@ static int mt7925_chip_reset(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, "%lld\n");
+static const u32 stats_query_mib_counters[] = {
+ UNI_CMD_MIB_CNT_RX_FCS_ERR,
+ UNI_CMD_MIB_CNT_RX_FIFO_OVERFLOW,
+ UNI_CMD_MIB_CNT_RX_MPDU,
+ UNI_CMD_MIB_CNT_AMPDU_RX_COUNT,
+ UNI_CMD_MIB_CNT_PF_DROP,
+ UNI_CMD_MIB_CNT_LEN_MISMATCH,
+ UNI_CMD_MIB_CNT_CHANNEL_IDLE,
+ UNI_CMD_MIB_CNT_CCA_NAV_TX_TIME,
+ UNI_CMD_MIB_CNT_MDRDY,
+ UNI_CMD_MIB_CNT_RX_CCK_MDRDY_TIME,
+ UNI_CMD_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME,
+ UNI_CMD_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME,
+ UNI_CMD_MIB_CNT_P_CCA_TIME,
+ UNI_CMD_MIB_CNT_S_CCA_TIME,
+ UNI_CMD_MIB_CNT_P_ED_TIME,
+ UNI_CMD_MIB_CNT_BCN_TX,
+ UNI_CMD_MIB_CNT_TX_BW_40MHZ,
+ UNI_CMD_MIB_CNT_TX_BW_80MHZ,
+ UNI_CMD_MIB_CNT_TX_BW_160MHZ,
+ UNI_CMD_MIB_CNT_BSS0_BA_MISS,
+ UNI_CMD_MIB_CNT_BSS0_RTS_TX_CNT,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY,
+ UNI_CMD_MIB_CNT_BSS0_FRAME_RETRY_2,
+ UNI_CMD_MIB_CNT_BSS0_RTS_RETRY,
+ UNI_CMD_MIB_CNT_BSS0_ACK_FAIL,
+ UNI_CMD_MIB_CNT_AMPDU,
+ UNI_CMD_MIB_CNT_AMPDU_MPDU,
+ UNI_CMD_MIB_CNT_AMPDU_ACKED,
+};
+
+/* Dump the whole firmware auto-rate table and mark the entry currently in use
+ * with "-->"
+ */
+static void
+mt7925_dump_auto_rate_table(struct seq_file *s,
+ const struct mt7925_wtbl_rate *wr)
+{
+ u8 fcap = wr->fcap;
+ u8 rate_idx = wr->rate_idx;
+ u8 cbrn = wr->cbrn;
+ int i;
+
+ seq_printf(s, "%-22s Cur Rate Index = %u\n", " ", rate_idx);
+
+ for (i = 0; i < MT7925_AUTO_RATE_NUM; i++) {
+ u16 rate_code = le16_to_cpu(wr->rate_code[i]);
+ u8 txmode = MT7925_HW_RATE_TO_MODE(rate_code);
+ u8 rate = MT7925_HW_RATE_TO_MCS(rate_code);
+ u8 nsts = MT7925_HW_RATE_TO_NSS(rate_code) + 1;
+ u8 stbc = MT7925_HW_RATE_TO_STBC(rate_code);
+ u8 dcm = MT7925_HW_RATE_TO_DCM(rate_code);
+ u8 ersu106t = MT7925_HW_RATE_TO_106T(rate_code);
+ u8 sgi = mt7925_wtbl_get_sgi(wr, txmode, fcap);
+ u8 ldpc = mt7925_wtbl_get_ldpc(wr, txmode);
+ const char *mode_str = "N/A";
+
+ if (dcm)
+ rate = MT7925_HW_RATE_UNMASK_DCM(rate);
+ if (ersu106t)
+ rate = MT7925_HW_RATE_UNMASK_106T(rate);
+
+ if (txmode < ARRAY_SIZE(mt7925_tx_mode_str))
+ mode_str = mt7925_tx_mode_str[txmode];
+
+ seq_printf(s, "Rate index[%d] %s", i,
+ rate_idx == i ? "--> " : " ");
+
+ /* rate/MCS field */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ",
+ mt7925_tx_rate_cck_str[rate & 0x3]);
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ seq_printf(s, "%s, ", mt7925_hw_rate_ofdm_str(rate));
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF)
+ seq_printf(s, "MCS%d, ", rate);
+ else
+ seq_printf(s, "%s%d_MCS%d, ",
+ stbc ? "NSTS" : "NSS", nsts, rate);
+
+ /* bandwidth: mirror the CCK/OFDM -> BW20 and cbrn handling */
+ if (txmode == MT7925_TX_RATE_MODE_CCK ||
+ txmode == MT7925_TX_RATE_MODE_OFDM)
+ seq_printf(s, "%s, ", mt7925_tx_rate_bw_str[0]);
+ else if (i > cbrn)
+ seq_printf(s, "%s, ",
+ fcap < 5 ?
+ (fcap > MT7925_BW_20 ?
+ mt7925_tx_rate_bw_str[fcap - 1] :
+ mt7925_tx_rate_bw_str[fcap]) :
+ mt7925_tx_rate_bw_str[5]);
+ else
+ seq_printf(s, "%s, ",
+ fcap < 5 ? mt7925_tx_rate_bw_str[fcap] :
+ mt7925_tx_rate_bw_str[5]);
+
+ /* GI / preamble */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ", rate < 4 ? "LP" : "SP");
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ ; /* OFDM has no GI/preamble to print */
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF ||
+ txmode == MT7925_TX_RATE_MODE_VHT ||
+ txmode == MT7925_TX_RATE_MODE_PLR)
+ seq_printf(s, "%s, ", sgi == 0 ? "LGI" : "SGI");
+ else
+ seq_printf(s, "%s, ",
+ sgi == 0 ? "SGI" :
+ (sgi == 1 ? "MGI" : "LGI"));
+
+ /* mode, DCM, 106t, STBC, coding */
+ seq_printf(s, "%s%s%s%s%s\n",
+ mode_str,
+ dcm ? ", DCM" : "", ersu106t ? ", 106t" : "",
+ stbc ? ", STBC, " : ", ",
+ (ldpc == 0 ||
+ txmode == MT7925_TX_RATE_MODE_CCK ||
+ txmode == MT7925_TX_RATE_MODE_OFDM) ?
+ "BCC" : "LDPC");
+ }
+}
+
+static int mt792x_stats(struct seq_file *s, void *data)
+{
+ s8 rssi = 0;
+ u8 band_idx = 0;
+ bool wtbl_rate_valid = false;
+ int ret = 0;
+ int i = 0;
+ u32 stats_value = 0;
+ u32 tx_link_speed_kbps = 0;
+ u32 tx_per_rem = 0;
+ __le32 tx_ampdu_cnt = 0;
+ u64 tx_total = 0;
+ u64 tx_fail = 0;
+ u64 tx_per = 0;
+ /* UNI_CMD_MIB_DATA */
+ u64 mib_values[ARRAY_SIZE(stats_query_mib_counters)];
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
+ struct mt7925_wtbl_rate wtbl_rate;
+ struct mt7925_sta_stats *stats = NULL;
+
+ band_idx = dev->mphy.band_idx;
+
+ if (band_idx >= MT7925_STA_STATS_BAND_NUM)
+ return -EINVAL;
+
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats)
+ return -ENOMEM;
+
+ /* Get STA_STATS */
+ mt792x_mutex_acquire(dev);
+ ret = mt792x_mcu_get_stat(dev, stats);
+ mt792x_mutex_release(dev);
+ if (ret)
+ goto out;
+
+ /* Get MIB_STATS */
+ mt792x_mutex_acquire(dev);
+ ret = mt7925_mcu_get_mib_info(dev,
+ band_idx,
+ stats_query_mib_counters,
+ ARRAY_SIZE(stats_query_mib_counters),
+ mib_values);
+ mt792x_mutex_release(dev);
+ if (ret)
+ goto out;
+
+ /* Get Link_Speed and RSSI */
+ mt792x_mutex_acquire(dev);
+ ret = mt7925_mcu_get_link_quality(dev,
+ stats->bss_idx,
+ &rssi,
+ &tx_link_speed_kbps);
+ mt792x_mutex_release(dev);
+ if (ret)
+ goto out;
+
+ /* Get the firmware auto-rate table (best effort; do not abort the
+ * whole stats dump if the WTBL query is not available).
+ */
+ mt792x_mutex_acquire(dev);
+ if (!mt792x_mcu_get_wtbl_rate(dev, stats->wtbl_idx, &wtbl_rate))
+ wtbl_rate_valid = true;
+ mt792x_mutex_release(dev);
+
+ /* Print STA_STATS info */
+ seq_printf(s, "(STA) connected AP MAC Address = %pM\n",
+ stats->mac_addr);
+ seq_printf(s, "%-22s BssIdx = [%u]\n", " ", stats->bss_idx);
+ seq_printf(s, "%-22s StaRecIdx = [%u]\n",
+ " ", stats->sta_idx);
+ seq_printf(s, "%-22s RSSI = %d\n", " ", rssi);
+ seq_printf(s, "%-22s Link_Speed = %u (kbit/s)\n",
+ " ", tx_link_speed_kbps);
+
+ seq_printf(s, "%-22s temperature = %u\n",
+ " ", stats->temperature);
+
+ stats_value = le32_to_cpu(stats->transmit_count) -
+ le32_to_cpu(stats->transmit_fail_count);
+ seq_printf(s, "%-22s Tx success = %u\n",
+ " ", stats_value);
+
+ stats_value = le32_to_cpu(stats->tx_fail_count) -
+ le32_to_cpu(stats->tx_life_timeout_count);
+ seq_printf(s, "%-22s Tx fail to Rcv ACK after retry = %u\n",
+ " ", stats_value);
+
+ seq_printf(s, "%-22s Rx Mpdu = %u\n",
+ " ", le32_to_cpu(stats->mib[band_idx].rx_mpdu_cnt));
+
+ seq_printf(s, "%-22s Rx Fcs Error = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].fcs_error));
+ seq_printf(s, "%-22s Rx FIFO full = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].rx_fifo_full));
+
+ for (i = 0; i < STAT_MIB_CNT_TRX_AGG_RANGE_MAX_NUM; i++) {
+ tx_ampdu_cnt = stats->mib[band_idx].tx_range_ampdu_cnt[i];
+ seq_printf(s, "%-22s TRX_AGG_RANGE[%d] = %u (PPDU)\n",
+ " ",
+ i,
+ le32_to_cpu(tx_ampdu_cnt));
+ }
+
+ seq_printf(s, "%-22s MPDUs in AMPDUs transmitted = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].ampdu_tx_sf_cnt));
+ seq_printf(s, "%-22s MPDUs in AMPDUs transmitted with ACK reply = %u (MPDU)\n",
+ " ", le32_to_cpu(stats->mib[band_idx].ampdu_tx_ack_sf_cnt));
+ seq_printf(s, "%-22s rate1_tx_cnt = %u\n",
+ " ", le32_to_cpu(stats->rate1_tx_cnt));
+ seq_printf(s, "%-22s rate1_fail_cnt = %u\n",
+ " ", le32_to_cpu(stats->rate1_fail_cnt));
+ seq_printf(s, "%-22s train_up = %u\n",
+ " ", le16_to_cpu(stats->train_up));
+ seq_printf(s, "%-22s train_down = %u\n",
+ " ", le16_to_cpu(stats->train_down));
+ seq_printf(s, "%-22s is_force_tx_stream = %u\n",
+ " ", stats->is_force_tx_stream);
+ seq_printf(s, "%-22s is_force_se_off = %u\n",
+ " ", stats->is_force_se_off);
+ seq_printf(s, "%-22s max_ampdu_factor = %u\n",
+ " ", stats->max_ampdu_factor);
+ seq_printf(s, "%-22s tx_rate_up_penalty = %u\n",
+ " ", stats->tx_rate_up_penalty);
+ seq_printf(s, "%-22s low_traffic_mode = %u\n",
+ " ", stats->low_traffic_mode);
+ seq_printf(s, "%-22s low_traffic_count = %u\n",
+ " ", stats->low_traffic_count);
+ seq_printf(s, "%-22s low_traffic_dashboard = %u\n",
+ " ", stats->low_traffic_dashboard);
+ seq_printf(s, "%-22s dynamic_sgi_state = %u\n",
+ " ", stats->dynamic_sgi_state);
+ seq_printf(s, "%-22s dynamic_sgi_score = %u\n",
+ " ", stats->dynamic_sgi_score);
+ seq_printf(s, "%-22s dynamic_bw_state = %u\n",
+ " ", stats->dynamic_bw_state);
+ seq_printf(s, "%-22s dynamic_gband_256qam_state = %u\n",
+ " ", stats->dynamic_gband_256qam_state);
+ seq_printf(s, "%-22s vht_non_sp_rate_state = %u\n",
+ " ", stats->vht_non_sp_rate_state);
+
+ /* Decode the TX Vector BBP latch to show the current TX MCS rate */
+ mt7925_print_last_tx_rate(s, stats->tx_vector[band_idx].txv);
+
+ /* Dump the whole firmware auto-rate table
+ * and mark the entry currently in use.
+ */
+ if (wtbl_rate_valid)
+ mt7925_dump_auto_rate_table(s, &wtbl_rate);
+
+ seq_puts(s, "\nmib state:\n");
+ /* ===Rx Related Counters=== */
+ seq_puts(s, "=== Rx Related Counters ===\n");
+ seq_printf(s, "%-22s Rx with CRC = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_FCS_ERR]);
+ seq_printf(s, "%-22s Rx drop due to out of resource = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_FIFO_OVERFLOW]);
+ seq_printf(s, "%-22s Rx Mpdu = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_MPDU]);
+ seq_printf(s, "%-22s Rx AMpdu = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU_RX_COUNT]);
+ seq_printf(s, "%-22s Rx PF Drop = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_PF_DROP]);
+ seq_printf(s, "%-22s Rx Len Mismatch = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_LEN_MISMATCH]);
+
+ /* ===Phy/Timing Related Counters=== */
+ seq_puts(s, "\n=== Phy/Timing Related Counters ===\n");
+ seq_printf(s, "%-22s ChannelIdleCnt = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_CHANNEL_IDLE]);
+ seq_printf(s, "%-22s CCA_NAV_Tx_Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_CCA_NAV_TX_TIME]);
+ seq_printf(s, "%-22s Rx_MDRDY_CNT = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_MDRDY]);
+ seq_printf(s, "%-22s CCK_MDRDY = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_CCK_MDRDY_TIME]);
+ seq_printf(s, "%-22s OFDM_MDRDY = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME]);
+ seq_printf(s, "%-22s OFDM_GREEN_MDRDY = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME]);
+ seq_printf(s, "%-22s Prim CCA Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_P_CCA_TIME]);
+ seq_printf(s, "%-22s Sec CCA Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_S_CCA_TIME]);
+ seq_printf(s, "%-22s Prim ED Time = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_P_ED_TIME]);
+
+ /* ===Tx Related Counters(Generic)=== */
+ seq_puts(s, "\n=== Tx Related Counters(Generic) ===\n");
+ seq_printf(s, "%-22s BeaconTxCnt = %llu\n",
+ " ", mib_values[QUERY_MIB_CNT_BCN_TX]);
+ seq_printf(s, "%-22s Tx 40MHz Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_TX_BW_40MHZ]);
+ seq_printf(s, "%-22s Tx 80MHz Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_TX_BW_80MHZ]);
+ seq_printf(s, "%-22s Tx 160MHz Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_TX_BW_160MHZ]);
+
+ /* ===BSSID[0] Related Counters=== */
+ seq_puts(s, "\n=== BSSID[0] Related Counters ===\n");
+ seq_printf(s, "%-22s BA Miss Cnt = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_BA_MISS]);
+ seq_printf(s, "%-22s RTS Tx Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_RTS_TX_CNT]);
+ seq_printf(s, "%-22s Frame Retry Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_FRAME_RETRY]);
+ seq_printf(s, "%-22s Frame Retry 2 Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_FRAME_RETRY_2]);
+ seq_printf(s, "%-22s RTS Retry Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_RTS_RETRY]);
+ seq_printf(s, "%-22s Ack Failed Cnt = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_BSS0_ACK_FAIL]);
+
+ /* ===AMPDU Related Counters=== */
+ seq_puts(s, "\n=== AMPDU Related Counters ===\n");
+ seq_printf(s, "%-22s Tx AMPDU_Pkt_Cnt = %llu (PPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU]);
+ seq_printf(s, "%-22s Tx AMPDU_MPDU_Pkt_Cnt = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU_MPDU]);
+ seq_printf(s, "%-22s AMPDU Tx success = %llu (MPDU)\n",
+ " ", mib_values[QUERY_MIB_CNT_AMPDU_ACKED]);
+
+ tx_total = mib_values[QUERY_MIB_CNT_AMPDU_MPDU];
+ tx_fail = mib_values[QUERY_MIB_CNT_AMPDU_MPDU] -
+ mib_values[QUERY_MIB_CNT_AMPDU_ACKED];
+ tx_per = tx_total == 0 ? 0 : div64_u64(1000 * tx_fail, tx_total);
+ seq_printf(s, "%-22s AMPDU Tx fail count = %llu (MPDU), PER=%llu.%1llu%%\n",
+ " ",
+ tx_fail,
+ div_u64_rem(tx_per, 10, &tx_per_rem), (u64)tx_per_rem);
+
+out:
+ kfree(stats);
+ return ret;
+}
+
int mt7925_init_debugfs(struct mt792x_dev *dev)
{
struct dentry *dir;
@@ -313,5 +676,8 @@ int mt7925_init_debugfs(struct mt792x_dev *dev)
mt792x_pm_stats);
debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "stats", dir,
+ mt792x_stats);
+
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/stats.c b/drivers/net/wireless/mediatek/mt76/mt7925/stats.c
new file mode 100644
index 0000000000000..874c0b979c264
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/stats.c
@@ -0,0 +1,587 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/* Copyright (C) 2026 MediaTek Inc. */
+
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include "mt7925.h"
+#include "mcu.h"
+#include "mac.h"
+#include "stats.h"
+
+#define MT7925_STA_STATS_VERSION 1
+#define MT7925_STA_STATS_VALID 1U
+
+#define MT7925_MIB_MAX_CNT 32
+
+/* firmware UNI_CMD_MIB_CNT_MAX_NUM upper bound */
+#define MT7925_MIB_CNT_MAX_NUM 512
+
+#define MT7925_LQ_BAND_NUM 4 /* Link quality band */
+
+const char * const mt7925_tx_mode_str[] = {
+ "CCK", "OFDM", "MM", "GF", "VHT", "PLR",
+ "PLRP", "ALR", "HE_SU", "HE_ER", "HE_TRIG", "HE_MU",
+ "EHT_ER", "TOF", "EHT_TRIG", "EHT_MU"
+};
+
+const char * const mt7925_tx_rate_cck_str[] = {
+ "1M", "2M", "5.5M", "11M", "N/A"
+};
+
+const char * const mt7925_tx_rate_bw_str[] = {
+ "BW20", "BW40", "BW80", "BW160/BW8080", "BW320", "N/A"
+};
+
+struct mt7925_sta_stats_req {
+ u8 rsv[4];
+ __le16 tag;
+ __le16 len;
+ u8 sta_rec_idx;
+ u8 rsv1;
+ u8 lls_read_clear;
+ u8 reset_counter;
+} __packed;
+
+struct mt7925_sta_stats_event {
+ u8 rsv[4];
+ __le16 tag;
+ __le16 len;
+ struct mt7925_sta_stats stats;
+} __packed;
+
+/* WTBL auto-rate request TLV, mirror Gen4m struct UNI_CMD_STAT_WTBL.
+ * The RA tag reuses UNI_CMD_ID_STATISTICS_WTBL (10).
+ */
+struct mt7925_wtbl_rate_req {
+ u8 rsv[4];
+ __le16 tag;
+ __le16 len;
+ __le16 wlan_idx;
+ __le16 rsv1;
+} __packed;
+
+/* WTBL auto-rate event TLV. Firmware answers cmd tag 10 with event tag 12. */
+struct mt7925_wtbl_rate_event {
+ u8 rsv[4];
+ struct mt7925_wtbl_rate rate;
+} __packed;
+
+/* fixed field, mirror UNI_(CMD|EVENT)_MIB_INFO */
+struct mt7925_mib_hdr {
+ u8 band_idx;
+ u8 rsv[3];
+} __packed;
+
+/* One requested/returned MIB counter, mirror UNI_(CMD|EVENT)_MIB_DATA_T. */
+struct mt7925_mib_data {
+ __le16 tag; /* UNI_(CMD|EVENT)_MIB_DATA = 0 */
+ __le16 len;
+ __le32 counter; /* MIB counter ID (enum mt7925_mib_counter) */
+ __le64 data; /* only valid on event; ignored on cmd */
+} __packed;
+
+/* per-band link quality entry, mirror UNI_LINK_QUALITY */
+struct mt7925_link_quality {
+ s8 rssi; /* moving-average beacon RSSI of connected AP */
+ s8 link_quality; /* always 0 */
+ __le16 link_speed; /* TX rate1, unit 500 Kb/s */
+ u8 medium_busy_pct; /* always 0 */
+ u8 is_ready; /* 0: fields invalid, 1: valid */
+ u8 rsv[2];
+} __packed;
+
+/* request TLV, mirror UNI_CMD_LINK_QUALITY (header + tag/len only) */
+struct mt7925_lq_req {
+ u8 rsv[4]; /* UNI_CMD_GET_STATISTICS fixed field */
+ __le16 tag; /* UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1 */
+ __le16 len;
+} __packed;
+
+/* event TLV, mirror UNI_EVENT_LINK_QUALITY */
+struct mt7925_lq_event {
+ u8 rsv[4]; /* UNI_EVENT_STATISTICS fixed field */
+ __le16 tag; /* UNI_EVENT_ID_STATISTICS_LINK_QUALITY = 1 */
+ __le16 len;
+ struct mt7925_link_quality lq[MT7925_LQ_BAND_NUM];
+} __packed;
+
+static void
+mt7925_get_ap_sta_rec_idx_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mt7925_sta_rec_lookup *lookup = data;
+ struct mt792x_vif *mvif;
+ struct mt792x_sta *msta;
+
+ if (lookup->sta_rec_idx >= 0)
+ return;
+
+ if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
+ return;
+
+ mvif = (struct mt792x_vif *)vif->drv_priv;
+ msta = mvif->wep_sta;
+ if (!msta)
+ return;
+
+ if (!msta->deflink.wcid.sta)
+ return;
+
+ lookup->sta_rec_idx = msta->deflink.wcid.idx;
+}
+
+int
+mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx)
+{
+ struct mt7925_sta_rec_lookup lookup = {
+ .sta_rec_idx = -1,
+ };
+
+ lockdep_assert_held(&dev->mt76.mutex);
+
+ ieee80211_iterate_active_interfaces(dev->mphy.hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7925_get_ap_sta_rec_idx_iter,
+ &lookup);
+
+ if (lookup.sta_rec_idx < 0)
+ return -ENOTCONN;
+
+ if (lookup.sta_rec_idx > U8_MAX)
+ return -ERANGE;
+
+ *sta_rec_idx = lookup.sta_rec_idx;
+
+ return 0;
+}
+
+/* Decode the TX Vector BBP latch and print the last TX rate */
+void
+mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3])
+{
+ const char *mode_str = "N/A";
+ u8 rate, txmode, frmode, sgi, ldpc, nsts, stbc, spe, dcm, ersu106t;
+ s8 txpwr, pos_txpwr;
+ u32 txv[3];
+
+ txv[0] = le32_to_cpu(le_txv[0]);
+ txv[1] = le32_to_cpu(le_txv[1]);
+ txv[2] = le32_to_cpu(le_txv[2]);
+
+ if (txv[0] == 0xffffffff) {
+ seq_printf(s, "%-22s %s = %s\n", " ", "Last TX Rate", "N/A");
+ seq_printf(s, "%-22s %s = %s\n",
+ " ", "Chip Out TX Power", "N/A");
+ return;
+ }
+
+ rate = MT7925_TXV_GET_TX_RATE(txv);
+ txmode = MT7925_TXV_GET_TX_MODE(txv);
+ frmode = MT7925_TXV_GET_TX_FRMODE(txv);
+ nsts = MT7925_TXV_GET_TX_NSTS(txv) + 1;
+ sgi = MT7925_TXV_GET_TX_SGI(txv);
+ ldpc = MT7925_TXV_GET_TX_LDPC(txv);
+ stbc = MT7925_TXV_GET_TX_STBC(txv);
+ txpwr = MT7925_TXV_GET_TX_PWR(txv);
+ spe = MT7925_TXV_GET_TX_SPE_IDX(txv);
+ dcm = MT7925_TXV_GET_TX_DCM(txv);
+ ersu106t = MT7925_TXV_GET_TX_106T(txv);
+
+ if (dcm)
+ rate = MT7925_TXV_RATE_UNMASK_DCM(rate);
+ if (ersu106t)
+ rate = MT7925_TXV_RATE_UNMASK_106T(rate);
+
+ if (txmode < ARRAY_SIZE(mt7925_tx_mode_str))
+ mode_str = mt7925_tx_mode_str[txmode];
+
+ seq_printf(s, "%-22s %s = ", " ", "Last TX Rate");
+
+ /* rate/MCS field */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ",
+ rate < 4 ? mt7925_tx_rate_cck_str[rate] :
+ (((rate >= 5) && (rate <= 7)) ?
+ mt7925_tx_rate_cck_str[rate - 4] :
+ mt7925_tx_rate_cck_str[4]));
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ seq_printf(s, "%s, ", mt7925_hw_rate_ofdm_str(rate));
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF)
+ seq_printf(s, "MCS%d, ", rate);
+ else
+ seq_printf(s, "%s%d_MCS%d, ",
+ stbc ? "NSTS" : "NSS", nsts, rate);
+
+ /* bandwidth */
+ seq_printf(s, "%s, ",
+ frmode < 5 ? mt7925_tx_rate_bw_str[frmode] :
+ mt7925_tx_rate_bw_str[5]);
+
+ /* GI / preamble */
+ if (txmode == MT7925_TX_RATE_MODE_CCK)
+ seq_printf(s, "%s, ", rate < 4 ? "LP" : "SP");
+ else if (txmode == MT7925_TX_RATE_MODE_OFDM)
+ ; /* OFDM has no GI/preamble to print */
+ else if (txmode == MT7925_TX_RATE_MODE_HTMIX ||
+ txmode == MT7925_TX_RATE_MODE_HTGF ||
+ txmode == MT7925_TX_RATE_MODE_VHT ||
+ txmode == MT7925_TX_RATE_MODE_PLR)
+ seq_printf(s, "%s, ", sgi == 0 ? "LGI" : "SGI");
+ else
+ seq_printf(s, "%s, ",
+ sgi == 0 ? "SGI" : (sgi == 1 ? "MGI" : "LGI"));
+
+ /* mode, DCM, 106t, STBC, coding, SPE */
+ seq_printf(s, "%s%s%s%s%s%s%d\n",
+ mode_str,
+ dcm ? ", DCM" : "", ersu106t ? ", 106t" : "",
+ stbc ? ", STBC, " : ", ", ldpc == 0 ? "BCC" : "LDPC",
+ ", SPE", spe);
+
+ /* chip out TX power (unit: 0.5 dBm) */
+ pos_txpwr = (txpwr < 0) ? (~txpwr + 1) : txpwr;
+ seq_printf(s, "%-22s %s = %c%d.%1d dBm\n",
+ " ", "Chip Out TX Power",
+ (txpwr < 0) ? '-' : '+',
+ (pos_txpwr / 2), 5 * (pos_txpwr % 2));
+}
+
+/* Guard interval used for the auto-rate entries, mirror Gen4m
+ * connac3x_get_sgi_info_from_fw(): pick the per-mode/per-BW flag.
+ */
+u8
+mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap)
+{
+ bool he = (txmode == MT7925_TX_RATE_MODE_HE_SU ||
+ txmode == MT7925_TX_RATE_MODE_HE_ER ||
+ txmode == MT7925_TX_RATE_MODE_HE_TRIG ||
+ txmode == MT7925_TX_RATE_MODE_HE_MU);
+ bool eht = (txmode == MT7925_TX_RATE_MODE_EHT_ER ||
+ txmode == MT7925_TX_RATE_MODE_EHT_TRIG ||
+ txmode == MT7925_TX_RATE_MODE_EHT_MU);
+
+ if (eht)
+ return wr->gi_eht;
+
+ switch (fcap) {
+ case MT7925_BW_20:
+ return he ? wr->g2_he : wr->g2;
+ case MT7925_BW_40:
+ return he ? wr->g4_he : wr->g4;
+ case MT7925_BW_80:
+ return he ? wr->g8_he : wr->g8;
+ case MT7925_BW_160:
+ return he ? wr->g16_he : wr->g16;
+ default:
+ return 0;
+ }
+}
+
+/* Coding used for the auto-rate entries, mirror Gen4m
+ * connac3x_wtbl_get_ldpc_info_from_fw(): 0 = BCC, 1 = LDPC.
+ */
+u8
+mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode)
+{
+ switch (txmode) {
+ case MT7925_TX_RATE_MODE_HTMIX:
+ case MT7925_TX_RATE_MODE_HTGF:
+ return wr->ht_ldpc;
+ case MT7925_TX_RATE_MODE_VHT:
+ return wr->vht_ldpc;
+ case MT7925_TX_RATE_MODE_HE_SU:
+ case MT7925_TX_RATE_MODE_HE_ER:
+ case MT7925_TX_RATE_MODE_HE_TRIG:
+ case MT7925_TX_RATE_MODE_HE_MU:
+ return wr->he_ldpc;
+ case MT7925_TX_RATE_MODE_EHT_ER:
+ case MT7925_TX_RATE_MODE_EHT_TRIG:
+ case MT7925_TX_RATE_MODE_EHT_MU:
+ return wr->eht_ldpc;
+ default:
+ return 0;
+ }
+}
+
+int mt792x_mcu_get_stat(struct mt792x_dev *dev,
+ struct mt7925_sta_stats *stats)
+{
+ u16 len = 0;
+ int ret = 0;
+ struct mt7925_sta_stats_event *event = NULL;
+ struct sk_buff *skb = NULL;
+ struct mt7925_sta_stats_req req = {
+ .tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_STA),
+ .len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),
+ .lls_read_clear = false,
+ .reset_counter = false,
+ };
+
+ ret = mt7925_get_ap_sta_rec_idx(dev, &req.sta_rec_idx);
+ if (ret)
+ return ret;
+
+ if (!stats)
+ return -EINVAL;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_STAT_INFO),
+ &req, sizeof(req), true, &skb);
+
+ if (ret)
+ return ret;
+
+ event = (struct mt7925_sta_stats_event *)skb->data;
+
+ if (le16_to_cpu(event->tag) != UNI_CMD_ID_STATISTICS_STA) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ len = le16_to_cpu(event->len);
+ if (len < sizeof(*event) - sizeof(event->rsv) ||
+ len > skb->len - sizeof(event->rsv) || !IS_ALIGNED(len, 4)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ if (event->stats.version != MT7925_STA_STATS_VERSION) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ if (!(le32_to_cpu(event->stats.flags) & MT7925_STA_STATS_VALID)) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ memcpy(stats, &event->stats, sizeof(*stats));
+
+out:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,
+ const u32 *counters, u8 counter_num,
+ u64 *values)
+{
+ u8 *req;
+ u8 *tlv, *tlv_end;
+ u16 req_len;
+ int i, ret;
+ struct mt7925_mib_hdr *req_hdr;
+ struct mt7925_mib_data *req_tlv;
+ struct sk_buff *skb;
+
+ if (!counters || !values || !counter_num ||
+ counter_num > MT7925_MIB_MAX_CNT)
+ return -EINVAL;
+
+ /* clear output; counters not returned by firmware stay 0 */
+ memset(values, 0, counter_num * sizeof(*values));
+
+ req_len = sizeof(struct mt7925_mib_hdr) +
+ counter_num * sizeof(struct mt7925_mib_data);
+
+ req = kzalloc(req_len, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req_hdr = (struct mt7925_mib_hdr *)req;
+ req_hdr->band_idx = band_idx;
+
+ req_tlv = (struct mt7925_mib_data *)(req + sizeof(*req_hdr));
+ for (i = 0; i < counter_num; i++) {
+ req_tlv[i].tag = cpu_to_le16(UNI_CMD_MIB_DATA);
+ req_tlv[i].len = cpu_to_le16(sizeof(struct mt7925_mib_data));
+ req_tlv[i].counter = cpu_to_le32(counters[i]);
+ }
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_MIB_INFO), req,
+ req_len, true, &skb);
+ kfree(req);
+ if (ret)
+ return ret;
+
+ if (skb->len < sizeof(struct mt7925_mib_hdr)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ /* walk the returned TLVs, match each counter ID to the request */
+ tlv = skb->data + sizeof(struct mt7925_mib_hdr);
+ tlv_end = skb->data + skb->len;
+
+ while (tlv + sizeof(struct mt7925_mib_data) <= tlv_end) {
+ struct mt7925_mib_data *evt_tlv =
+ (struct mt7925_mib_data *)tlv;
+ u16 tag = le16_to_cpu(evt_tlv->tag);
+ u16 len = le16_to_cpu(evt_tlv->len);
+ u32 counter;
+
+ if (len < sizeof(struct mt7925_mib_data) ||
+ tlv + len > tlv_end)
+ break;
+
+ if (tag == UNI_CMD_MIB_DATA) {
+ counter = le32_to_cpu(evt_tlv->counter);
+
+ if (counter < MT7925_MIB_CNT_MAX_NUM) {
+ for (i = 0; i < counter_num; i++) {
+ if (counters[i] == counter) {
+ values[i] =
+ le64_to_cpu(evt_tlv->data);
+ break;
+ }
+ }
+ }
+ }
+
+ tlv += len;
+ }
+
+ ret = 0;
+
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx)
+{
+ char * const ofdm_str[] = {
+ "6M", "9M", "12M", "18M", "24M", "36M", "48M", "54M", "N/A"
+ };
+
+ switch (ofdm_idx) {
+ case 11: return ofdm_str[0]; /* 6M */
+ case 15: return ofdm_str[1]; /* 9M */
+ case 10: return ofdm_str[2]; /* 12M */
+ case 14: return ofdm_str[3]; /* 18M */
+ case 9: return ofdm_str[4]; /* 24M */
+ case 13: return ofdm_str[5]; /* 36M */
+ case 8: return ofdm_str[6]; /* 48M */
+ case 12: return ofdm_str[7]; /* 54M */
+ default: return ofdm_str[8];
+ }
+}
+
+/* mt792x_mcu_get_wtbl_rate - fetch the firmware auto-rate table for a WCID
+ * @dev: device
+ * @wlan_idx: HW WTBL / WCID index (see mt7925_sta_stats.wtbl_idx)
+ * @rate: out, filled with the auto-rate table snapshot
+ *
+ * Mirror of Gen4m wlanoidGetStatWtbl(): send UNI_CMD_GET_STAT_INFO with the
+ * WTBL rate TLV (cmd tag 10) and parse the reply (event tag 12) into @rate.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,
+ struct mt7925_wtbl_rate *rate)
+{
+ int ret;
+ struct mt7925_wtbl_rate_event *event = NULL;
+ struct sk_buff *skb = NULL;
+ struct mt7925_wtbl_rate_req req = {
+ .tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_WTBL),
+ .len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),
+ .wlan_idx = cpu_to_le16(wlan_idx),
+ };
+
+ if (!rate)
+ return -EINVAL;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_STAT_INFO),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ if (skb->len < sizeof(*event)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ event = (struct mt7925_wtbl_rate_event *)skb->data;
+
+ if (le16_to_cpu(event->rate.tag) != MT7925_UNI_EVENT_STATISTICS_WTBL) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ memcpy(rate, &event->rate, sizeof(*rate));
+ ret = 0;
+
+out:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+/**
+ * mt7925_mcu_get_link_quality - query RSSI and TX link speed for a band
+ * @dev: device
+ * @band_idx: band/BSS index (0..3)
+ * @rssi: out, moving-average beacon RSSI in dBm (may be NULL)
+ * @tx_link_speed_kbps: out, TX rate in kbit/s (may be NULL)
+ *
+ * Return: 0 on success, -ENOENT if the band's link quality is not ready.
+ *
+ * Only RSSI and TX rate come from firmware here; for RX rate read wcid->rate.
+ */
+int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,
+ s8 *rssi, u32 *tx_link_speed_kbps)
+{
+ int ret;
+ struct mt7925_lq_event *event;
+ struct mt7925_link_quality *lq;
+ struct sk_buff *skb;
+ struct mt7925_lq_req req = {
+ .tag = cpu_to_le16(UNI_CMD_ID_STATISTICS_LINK_QUALITY),
+ .len = cpu_to_le16(sizeof(req) - sizeof(req.rsv)),
+ };
+
+ if (band_idx >= MT7925_LQ_BAND_NUM)
+ return -EINVAL;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_UNI_QUERY(GET_STAT_INFO), &req,
+ sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ if (skb->len < sizeof(*event)) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ event = (struct mt7925_lq_event *)skb->data;
+
+ if (le16_to_cpu(event->tag) != UNI_CMD_ID_STATISTICS_LINK_QUALITY) {
+ ret = -EPROTO;
+ goto out;
+ }
+
+ lq = &event->lq[band_idx];
+ if (!lq->is_ready) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (rssi)
+ *rssi = lq->rssi;
+
+ /* firmware reports TX rate in 500 Kb/s units -> kbit/s */
+ if (tx_link_speed_kbps)
+ *tx_link_speed_kbps = le16_to_cpu(lq->link_speed) * 500;
+
+ ret = 0;
+
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/stats.h b/drivers/net/wireless/mediatek/mt76/mt7925/stats.h
new file mode 100644
index 0000000000000..a70b9eb3aa806
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/stats.h
@@ -0,0 +1,309 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/* Copyright (C) 2026 MediaTek Inc. */
+
+#ifndef __MT7925_STATS_H
+#define __MT7925_STATS_H
+
+#include <linux/if_ether.h>
+#include <linux/types.h>
+#include "../mt76_connac_mcu.h"
+
+#define MT7925_STA_STATS_AC_NUM 4
+#define MT7925_STA_STATS_BAND_NUM 2
+#define MT7925_STA_STATS_AGG_RANGE_NUM 16
+#define MT7925_STA_STATS_TX_QUALITY_NUM 4
+#define MT7925_TX_MODE_NUM 16
+#define MT7925_TX_RATE_CCK_NUM 5
+#define MT7925_TX_RATE_BW_NUM 6
+
+/* HW rate code (16-bit) field extract, mirror Gen4m CONNAC3X_HW_TX_RATE_TO_*.
+ * The auto-rate table stores one rate code per entry.
+ */
+#define MT7925_HW_RATE_TO_MCS(_x) (((_x) & GENMASK(5, 0)) >> 0)
+#define MT7925_HW_RATE_TO_MODE(_x) (((_x) & GENMASK(9, 6)) >> 6)
+#define MT7925_HW_RATE_TO_NSS(_x) (((_x) & GENMASK(13, 10)) >> 10)
+#define MT7925_HW_RATE_TO_STBC(_x) (((_x) & BIT(14)) >> 14)
+#define MT7925_HW_RATE_TO_DCM(_x) (((_x) & BIT(4)) >> 4)
+#define MT7925_HW_RATE_TO_106T(_x) (((_x) & BIT(5)) >> 5)
+#define MT7925_HW_RATE_UNMASK_DCM(_r) ((u8)(_r) & 0xef)
+#define MT7925_HW_RATE_UNMASK_106T(_r) ((u8)(_r) & 0xdf)
+
+/* Number of entries in the firmware auto-rate table (mirror Gen4m
+ * AUTO_RATE_NUM). RA cycles through these and reports which one is in use
+ * via wtbl->rate_idx.
+ */
+#define MT7925_AUTO_RATE_NUM 8
+
+/* Firmware EVENT_STATISTICS sub-event tags. The WTBL rate request uses cmd tag
+ * UNI_CMD_ID_STATISTICS_WTBL (10) but the firmware replies with event tag 12.
+ */
+#define MT7925_UNI_EVENT_STATISTICS_WTBL 12
+
+/* CONNAC3X TX Vector BBP latch bit fields (mirror cmm_asic_connac3x.h).
+ * These operate on the 3-DWORD tx_vector[band].txv[3] array.
+ */
+#define MT7925_TXV_GET_TX_RATE(_txv) ((_txv)[2] & 0x7f)
+#define MT7925_TXV_GET_TX_LDPC(_txv) (((_txv)[2] & (0x1 << 7)) >> 7)
+#define MT7925_TXV_GET_TX_STBC(_txv) (((_txv)[0] & (0x3 << 6)) >> 6)
+#define MT7925_TXV_GET_TX_FRMODE(_txv) (((_txv)[0] & (0x7 << 8)) >> 8)
+#define MT7925_TXV_GET_TX_MODE(_txv) (((_txv)[0] & (0xf << 12)) >> 12)
+#define MT7925_TXV_GET_TX_NSTS(_txv) (((_txv)[2] & (0xfU << 28)) >> 28)
+#define MT7925_TXV_GET_TX_PWR(_txv) (((_txv)[0] & (0xff << 16)) >> 16)
+#define MT7925_TXV_GET_TX_SGI(_txv) (((_txv)[1] & (0x3 << 26)) >> 26)
+#define MT7925_TXV_GET_TX_SPE_IDX(_txv) (((_txv)[0] & (0x1f << 0)) >> 0)
+#define MT7925_TXV_GET_TX_DCM(_txv) (((_txv)[2] & (0x1 << 4)) >> 4)
+#define MT7925_TXV_GET_TX_106T(_txv) (((_txv)[2] & (0x1 << 5)) >> 5)
+#define MT7925_TXV_RATE_UNMASK_DCM(_r) ((u8)(_r) & 0xef)
+#define MT7925_TXV_RATE_UNMASK_106T(_r) ((u8)(_r) & 0xdf)
+
+extern const char * const mt7925_tx_mode_str[MT7925_TX_MODE_NUM];
+extern const char * const mt7925_tx_rate_cck_str[MT7925_TX_RATE_CCK_NUM];
+extern const char * const mt7925_tx_rate_bw_str[MT7925_TX_RATE_BW_NUM];
+
+/* TX rate mode, mirror Gen4m TX_RATE_MODE_* (see nic_rate.h). Used to decode
+ * both the TX Vector BBP latch and the firmware auto-rate table rate codes.
+ */
+enum mt7925_tx_rate_mode {
+ MT7925_TX_RATE_MODE_CCK = 0,
+ MT7925_TX_RATE_MODE_OFDM = 1,
+ MT7925_TX_RATE_MODE_HTMIX = 2,
+ MT7925_TX_RATE_MODE_HTGF = 3,
+ MT7925_TX_RATE_MODE_VHT = 4,
+ MT7925_TX_RATE_MODE_PLR = 5,
+ MT7925_TX_RATE_MODE_HE_SU = 8,
+ MT7925_TX_RATE_MODE_HE_ER = 9,
+ MT7925_TX_RATE_MODE_HE_TRIG = 10,
+ MT7925_TX_RATE_MODE_HE_MU = 11,
+ MT7925_TX_RATE_MODE_EHT_ER = 13,
+ MT7925_TX_RATE_MODE_EHT_TRIG = 14,
+ MT7925_TX_RATE_MODE_EHT_MU = 15,
+};
+
+enum {
+ UNI_CMD_MIB_DATA,
+};
+
+enum stats_query_mib_array_index {
+ QUERY_MIB_CNT_RX_FCS_ERR = 0,
+ QUERY_MIB_CNT_RX_FIFO_OVERFLOW,
+ QUERY_MIB_CNT_RX_MPDU,
+ QUERY_MIB_CNT_AMPDU_RX_COUNT,
+ QUERY_MIB_CNT_PF_DROP,
+ QUERY_MIB_CNT_LEN_MISMATCH,
+ QUERY_MIB_CNT_CHANNEL_IDLE,
+ QUERY_MIB_CNT_CCA_NAV_TX_TIME,
+ QUERY_MIB_CNT_MDRDY,
+ QUERY_MIB_CNT_RX_CCK_MDRDY_TIME,
+ QUERY_MIB_CNT_RX_OFDM_LG_MIXED_MDRDY_TIME,
+ QUERY_MIB_CNT_RX_OFDM_GREEN_MDRDY_TIME,
+ QUERY_MIB_CNT_P_CCA_TIME,
+ QUERY_MIB_CNT_S_CCA_TIME,
+ QUERY_MIB_CNT_P_ED_TIME,
+ QUERY_MIB_CNT_BCN_TX,
+ QUERY_MIB_CNT_TX_BW_40MHZ,
+ QUERY_MIB_CNT_TX_BW_80MHZ,
+ QUERY_MIB_CNT_TX_BW_160MHZ,
+ QUERY_MIB_CNT_BSS0_BA_MISS,
+ QUERY_MIB_CNT_BSS0_RTS_TX_CNT,
+ QUERY_MIB_CNT_BSS0_FRAME_RETRY,
+ QUERY_MIB_CNT_BSS0_FRAME_RETRY_2,
+ QUERY_MIB_CNT_BSS0_RTS_RETRY,
+ QUERY_MIB_CNT_BSS0_ACK_FAIL,
+ QUERY_MIB_CNT_AMPDU,
+ QUERY_MIB_CNT_AMPDU_MPDU,
+ QUERY_MIB_CNT_AMPDU_ACKED,
+ QUERY_MIB_CNT_MAX_NUM,
+};
+
+enum stats_trx_agg_range {
+ STAT_MIB_CNT_TRX_AGG_RANGE0_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE1_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE2_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE3_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE4_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE5_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE6_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE7_IDX,
+ STAT_MIB_CNT_TRX_AGG_RANGE_MAX_NUM
+};
+
+enum {
+ MT7925_BW_20 = 0,
+ MT7925_BW_40,
+ MT7925_BW_80,
+ MT7925_BW_160,
+};
+
+struct mt7925_sta_stats_ac {
+ __le32 tx_fail;
+ __le32 tx_retry;
+} __packed;
+
+struct mt7925_sta_stats_tx_vector {
+ __le32 txv[3];
+} __packed;
+
+struct mt7925_sta_stats_mib {
+ __le32 rx_mpdu_cnt;
+ __le32 fcs_error;
+ __le32 rx_fifo_full;
+ __le32 ampdu_tx_sf_cnt;
+ __le32 ampdu_tx_ack_sf_cnt;
+ __le32 tx_range_ampdu_cnt[MT7925_STA_STATS_AGG_RANGE_NUM];
+} __packed;
+
+/* Firmware EVENT_STA_STATISTICS body. */
+struct mt7925_sta_stats {
+ u8 version;
+ u8 rsv[3];
+ __le32 flags;
+
+ u8 sta_idx;
+ u8 bss_idx;
+ u8 wtbl_idx;
+ u8 rsv1;
+
+ u8 mac_addr[ETH_ALEN];
+ u8 per;
+ u8 rcpi;
+
+ __le32 phy_mode;
+ __le16 link_speed; /* 0.5 Mbit/s units */
+ u8 link_quality;
+ u8 link_reserved;
+
+ __le32 tx_count;
+ __le32 tx_fail_count;
+ __le32 tx_life_timeout_count;
+ __le32 tx_done_air_time;
+ __le32 transmit_count;
+ __le32 transmit_fail_count;
+
+ struct mt7925_sta_stats_ac ac[MT7925_STA_STATS_AC_NUM];
+
+ u8 temperature;
+ u8 skip_ar;
+ u8 ar_table_idx;
+ u8 rate_entry_idx;
+ u8 rate_entry_idx_prev;
+ u8 tx_sgi_detect_pass_cnt;
+ u8 ave_per;
+ u8 rsv2;
+
+ __le32 agg_range_ctrl[2];
+ u8 range_mode;
+ u8 rsv3[3];
+ __le32 agg_range_ctrl_ext[6];
+
+ u8 ar_state_curr;
+ u8 ar_state_prev;
+ u8 ar_action_type;
+ u8 highest_rate_cnt;
+ u8 lowest_rate_cnt;
+ u8 rsv4;
+ __le16 train_up;
+ __le16 train_down;
+ u8 rsv5[2];
+ __le32 rate1_tx_cnt;
+ __le32 rate1_fail_cnt;
+
+ struct mt7925_sta_stats_tx_vector tx_vector[MT7925_STA_STATS_BAND_NUM];
+ struct mt7925_sta_stats_mib mib[MT7925_STA_STATS_BAND_NUM];
+
+ u8 is_force_tx_stream;
+ u8 is_force_se_off;
+ __le16 ra_running_cnt;
+ u8 ra_status;
+ u8 max_ampdu_factor;
+ u8 tx_quality[MT7925_STA_STATS_TX_QUALITY_NUM];
+ u8 tx_rate_up_penalty;
+ u8 low_traffic_mode;
+ u8 low_traffic_count;
+ u8 low_traffic_dashboard;
+ u8 dynamic_sgi_state;
+ u8 dynamic_sgi_score;
+ u8 dynamic_bw_state;
+ u8 dynamic_gband_256qam_state;
+ u8 vht_non_sp_rate_state;
+ u8 rsv6[3];
+ u8 rsv7[2];
+} __packed;
+
+struct mt7925_sta_rec_lookup {
+ int sta_rec_idx;
+};
+
+/* Firmware auto-rate table snapshot, mirror Gen4m struct UNI_EVENT_STAT_WTBL.
+ *
+ * The firmware RA maintains up to MT7925_AUTO_RATE_NUM candidate rates in
+ * rate_code[]. rate_idx tells which entry is currently in use, so a dump can
+ * point at it with "-->". fcap is the bandwidth capability and the ldpc/sgi
+ * flags describe the per-mode coding/guard-interval used for those rates.
+ */
+struct mt7925_wtbl_rate {
+ __le16 tag;
+ __le16 len;
+ u8 rx_rcpi0;
+ u8 rx_rcpi1;
+ u8 cbrn;
+ u8 fcap;
+ u8 spe_idx;
+ u8 g2; /* SGI enabled, non-HE, BW20 */
+ u8 g4; /* SGI enabled, non-HE, BW40 */
+ u8 g8; /* SGI enabled, non-HE, BW80 */
+ u8 g16; /* SGI enabled, non-HE, BW160 */
+ u8 g2_he; /* GI, HE, BW20 */
+ u8 g4_he; /* GI, HE, BW40 */
+ u8 g8_he; /* GI, HE, BW80 */
+ u8 g16_he; /* GI, HE, BW160 */
+ u8 gi_eht; /* GI, EHT */
+ u8 ht_ldpc;
+ u8 vht_ldpc;
+ u8 he_ldpc;
+ u8 eht_ldpc;
+ u8 af;
+ u8 rate_idx; /* index into rate_code[] currently in use */
+ __le16 rate_code[MT7925_AUTO_RATE_NUM];
+ __le32 rsv[4];
+} __packed;
+
+int
+mt7925_get_ap_sta_rec_idx(struct mt792x_dev *dev, u8 *sta_rec_idx);
+
+void
+mt7925_print_last_tx_rate(struct seq_file *s, const __le32 le_txv[3]);
+
+u8
+mt7925_wtbl_get_sgi(const struct mt7925_wtbl_rate *wr, u8 txmode, u8 fcap);
+
+u8
+mt7925_wtbl_get_ldpc(const struct mt7925_wtbl_rate *wr, u8 txmode);
+
+char *mt7925_hw_rate_ofdm_str(u8 ofdm_idx);
+
+int mt792x_mcu_get_wtbl_rate(struct mt792x_dev *dev, u16 wlan_idx,
+ struct mt7925_wtbl_rate *rate);
+
+int mt792x_mcu_get_stat(struct mt792x_dev *dev,
+ struct mt7925_sta_stats *stats);
+
+int mt7925_mcu_get_mib_info(struct mt792x_dev *dev, u8 band_idx,
+ const u32 *counters, u8 counter_num,
+ u64 *values);
+
+/* GET_STAT_INFO (UNI_CMD_ID_GET_STATISTICS = 0x23),
+ * sub-command UNI_CMD_GET_STATISTICS_TAG_LINK_QUALITY = 1.
+ *
+ * @band_idx: band/BSS index (0..3)
+ * @rssi: out, moving-average beacon RSSI (dBm), may be NULL
+ * @tx_link_speed_kbps: out, TX link speed in kbit/s, may be NULL
+ *
+ * Returns 0 on success, -ENOENT if the band's link quality is not ready.
+ *
+ * NOTE: firmware provides only RSSI and TX rate here. RX rate/bandwidth are
+ * not in this event; read wcid->rate for the RX rate.
+ */
+int mt7925_mcu_get_link_quality(struct mt792x_dev *dev, u8 band_idx,
+ s8 *rssi, u32 *tx_link_speed_kbps);
+
+#endif
|
| 57/3 | 2026/08/31 03:58 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 26244 output: 378 thoughts: 3475 Thoughts: **KMSAN Assessment: Debugfs Statistics for MT7925 Wireless Driver** Right, let me break this down. My task is to determine if this patch necessitates a KMSAN fuzzing session. After thoroughly reviewing the code, it looks like this patch introduces debugfs functionality for the mt7925 wireless driver, specifically focusing on statistical data and corresponding MCU queries. It's adding enumerations for statistical IDs, linking new object files, and most importantly, implementing debugfs entries to display statistics. This includes functions to dump auto-rate tables, present station statistics, and query the MCU for various data like MIB counters, link quality, and wireless table rates. My key concern is whether this introduces any uninitialized memory reads or information leaks, which is where KMSAN shines. So, let’s dig into the memory handling. I'm seeing `kzalloc` used for dynamic allocations of `stats` and in `mt7925_mcu_get_mib_info` for the `req` structure. `stats` and `req` are fully initialized. All request structs (e.g. `mt7925_sta_stats_req`, `mt7925_wtbl_rate_req`, `mt7925_lq_req`) are initialized with designated initializers - which zero-initialize any unmentioned fields. Importantly, the stack variable `mib_values` is zeroed out by `memset` *before* any data is written to it in `mt7925_mcu_get_mib_info`. The stack allocated `wtbl_rate` is only used if `mt792x_mcu_get_wtbl_rate` succeeds, in which case it is populated with a `memcpy` of the MCU event data. The functions `mt7925_get_ap_sta_rec_idx`, `mt7925_mcu_get_link_quality`, are carefully handled, with checks and error codes to ensure initialization and validity. There are no raw binary memory copies or other unsafe operations. The output to user space relies exclusively on `seq_printf` and `seq_puts`, formatting values into text for display, mitigating concerns of uninitialized memory leakage to user space. After detailed examination, I am confident there are no uninitialized memory reads or leaks here, which are the primary targets of KMSAN. Any possible errors with the parsing of the MCU data or buffer overflow scenarios would be memory safety issues, and would likely be caught by KASAN. KMSAN is overkill in this situation. Therefore, the conclusion is: `NeedsKMSAN=false`. |
| 58/3 | 2026/08/31 03:58 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch adds debugfs statistics reporting and MCU query helpers for the mt7925 driver (including station statistics, MIB counters, link quality, and auto-rate table dumping).\n\nEvaluation of KMSAN vs KASAN applicability:\n1. Memory Initialization:\n - Heap allocations use kzalloc() (e.g., stats buffer and MIB request buffer).\n - Stack request structures (mt7925_sta_stats_req, mt7925_wtbl_rate_req, mt7925_lq_req) are initialized using C designated initializers, ensuring all omitted fields and padding are zeroed.\n - Stack arrays such as mib_values are explicitly zeroed via memset() at the entry of mt7925_mcu_get_mib_info().\n - Stack struct wtbl_rate is only read if mt792x_mcu_get_wtbl_rate() returns 0 (which copies the full struct from firmware response skb), guarded by the boolean flag wtbl_rate_valid.\n2. User-Space Exposure:\n - Output to user space is handled exclusively through seq_printf/seq_puts via debugfs seq_file entries (converting data to formatted ASCII strings). There are no raw binary structure copies or memory leaks to user space (no copy_to_user or raw netlink/ioctl transfers).\n3. Any potential bugs related to MCU skb parsing or array indices are bounds/memory corruption issues covered by standard KASAN.\n\nBecause no uninitialized memory reads or info-leaks are introduced, a dedicated KMSAN session is not required.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch adds debugfs statistics reporting and MCU query helpers for the mt7925 driver (including station statistics, MIB counters, link quality, and auto-rate table dumping).\n\nEvaluation of KMSAN vs KASAN applicability:\n1. Memory Initialization:\n - Heap allocations use kzalloc() (e.g., stats buffer and MIB request buffer).\n - Stack request structures (mt7925_sta_stats_req, mt7925_wtbl_rate_req, mt7925_lq_req) are initialized using C designated initializers, ensuring all omitted fields and padding are zeroed.\n - Stack arrays such as mib_values are explicitly zeroed via memset() at the entry of mt7925_mcu_get_mib_info().\n - Stack struct wtbl_rate is only read if mt792x_mcu_get_wtbl_rate() returns 0 (which copies the full struct from firmware response skb), guarded by the boolean flag wtbl_rate_valid.\n2. User-Space Exposure:\n - Output to user space is handled exclusively through seq_printf/seq_puts via debugfs seq_file entries (converting data to formatted ASCII strings). There are no raw binary structure copies or memory leaks to user space (no copy_to_user or raw netlink/ioctl transfers).\n3. Any potential bugs related to MCU skb parsing or array indices are bounds/memory corruption issues covered by standard KASAN.\n\nBecause no uninitialized memory reads or info-leaks are introduced, a dedicated KMSAN session is not required.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|