1 // SPDX-License-Identifier: ISC 2 /* Copyright (C) 2020 MediaTek Inc. */ 3 4 #include "mt7921.h" 5 #include "eeprom.h" 6 7 static int 8 mt7921_fw_debug_set(void *data, u64 val) 9 { 10 struct mt7921_dev *dev = data; 11 12 dev->fw_debug = (u8)val; 13 14 mt7921_mcu_fw_log_2_host(dev, dev->fw_debug); 15 16 return 0; 17 } 18 19 static int 20 mt7921_fw_debug_get(void *data, u64 *val) 21 { 22 struct mt7921_dev *dev = data; 23 24 *val = dev->fw_debug; 25 26 return 0; 27 } 28 29 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7921_fw_debug_get, 30 mt7921_fw_debug_set, "%lld\n"); 31 32 static void 33 mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy, 34 struct seq_file *file) 35 { 36 struct mt7921_dev *dev = file->private; 37 int bound[15], range[4], i; 38 39 if (!phy) 40 return; 41 42 /* Tx ampdu stat */ 43 for (i = 0; i < ARRAY_SIZE(range); i++) 44 range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i)); 45 46 for (i = 0; i < ARRAY_SIZE(bound); i++) 47 bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1; 48 49 seq_printf(file, "\nPhy0\n"); 50 51 seq_printf(file, "Length: %8d | ", bound[0]); 52 for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) 53 seq_printf(file, "%3d -%3d | ", 54 bound[i] + 1, bound[i + 1]); 55 56 seq_puts(file, "\nCount: "); 57 for (i = 0; i < ARRAY_SIZE(bound); i++) 58 seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); 59 seq_puts(file, "\n"); 60 61 seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); 62 } 63 64 static int 65 mt7921_tx_stats_show(struct seq_file *file, void *data) 66 { 67 struct mt7921_dev *dev = file->private; 68 int stat[8], i, n; 69 70 mt7921_ampdu_stat_read_phy(&dev->phy, file); 71 72 /* Tx amsdu info */ 73 seq_puts(file, "Tx MSDU stat:\n"); 74 for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { 75 stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); 76 n += stat[i]; 77 } 78 79 for (i = 0; i < ARRAY_SIZE(stat); i++) { 80 seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ", 81 i + 1, stat[i]); 82 if (n != 0) 83 seq_printf(file, "(%d%%)\n", stat[i] * 100 / n); 84 else 85 seq_puts(file, "\n"); 86 } 87 88 return 0; 89 } 90 91 DEFINE_SHOW_ATTRIBUTE(mt7921_tx_stats); 92 93 static int 94 mt7921_queues_acq(struct seq_file *s, void *data) 95 { 96 struct mt7921_dev *dev = dev_get_drvdata(s->private); 97 int i; 98 99 for (i = 0; i < 16; i++) { 100 int j, acs = i / 4, index = i % 4; 101 u32 ctrl, val, qlen = 0; 102 103 val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); 104 ctrl = BIT(31) | BIT(15) | (acs << 8); 105 106 for (j = 0; j < 32; j++) { 107 if (val & BIT(j)) 108 continue; 109 110 mt76_wr(dev, MT_PLE_FL_Q0_CTRL, 111 ctrl | (j + (index << 5))); 112 qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, 113 GENMASK(11, 0)); 114 } 115 seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); 116 } 117 118 return 0; 119 } 120 121 static int 122 mt7921_queues_read(struct seq_file *s, void *data) 123 { 124 struct mt7921_dev *dev = dev_get_drvdata(s->private); 125 struct { 126 struct mt76_queue *q; 127 char *queue; 128 } queue_map[] = { 129 { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" }, 130 { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" }, 131 { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" }, 132 }; 133 int i; 134 135 for (i = 0; i < ARRAY_SIZE(queue_map); i++) { 136 struct mt76_queue *q = queue_map[i].q; 137 138 if (!q) 139 continue; 140 141 seq_printf(s, 142 "%s: queued=%d head=%d tail=%d\n", 143 queue_map[i].queue, q->queued, q->head, 144 q->tail); 145 } 146 147 return 0; 148 } 149 150 static int 151 mt7921_pm_set(void *data, u64 val) 152 { 153 struct mt7921_dev *dev = data; 154 struct mt76_phy *mphy = dev->phy.mt76; 155 int ret = 0; 156 157 mt7921_mutex_acquire(dev); 158 159 dev->pm.enable = val; 160 161 ieee80211_iterate_active_interfaces(mphy->hw, 162 IEEE80211_IFACE_ITER_RESUME_ALL, 163 mt7921_pm_interface_iter, mphy->priv); 164 mt7921_mutex_release(dev); 165 166 return ret; 167 } 168 169 static int 170 mt7921_pm_get(void *data, u64 *val) 171 { 172 struct mt7921_dev *dev = data; 173 174 *val = dev->pm.enable; 175 176 return 0; 177 } 178 179 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n"); 180 181 static int 182 mt7921_pm_idle_timeout_set(void *data, u64 val) 183 { 184 struct mt7921_dev *dev = data; 185 186 dev->pm.idle_timeout = msecs_to_jiffies(val); 187 188 return 0; 189 } 190 191 static int 192 mt7921_pm_idle_timeout_get(void *data, u64 *val) 193 { 194 struct mt7921_dev *dev = data; 195 196 *val = jiffies_to_msecs(dev->pm.idle_timeout); 197 198 return 0; 199 } 200 201 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get, 202 mt7921_pm_idle_timeout_set, "%lld\n"); 203 204 static int mt7921_config(void *data, u64 val) 205 { 206 struct mt7921_dev *dev = data; 207 int ret; 208 209 mt7921_mutex_acquire(dev); 210 ret = mt76_connac_mcu_chip_config(&dev->mt76); 211 mt7921_mutex_release(dev); 212 213 return ret; 214 } 215 216 DEFINE_DEBUGFS_ATTRIBUTE(fops_config, NULL, mt7921_config, "%lld\n"); 217 218 int mt7921_init_debugfs(struct mt7921_dev *dev) 219 { 220 struct dentry *dir; 221 222 dir = mt76_register_debugfs(&dev->mt76); 223 if (!dir) 224 return -ENOMEM; 225 226 debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, 227 mt7921_queues_read); 228 debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, 229 mt7921_queues_acq); 230 debugfs_create_file("tx_stats", 0400, dir, dev, &mt7921_tx_stats_fops); 231 debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); 232 debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm); 233 debugfs_create_file("idle-timeout", 0600, dir, dev, 234 &fops_pm_idle_timeout); 235 debugfs_create_file("chip_config", 0600, dir, dev, &fops_config); 236 237 return 0; 238 } 239