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 mt7921_mutex_acquire(dev); 13 14 dev->fw_debug = (u8)val; 15 mt7921_mcu_fw_log_2_host(dev, dev->fw_debug); 16 17 mt7921_mutex_release(dev); 18 19 return 0; 20 } 21 22 static int 23 mt7921_fw_debug_get(void *data, u64 *val) 24 { 25 struct mt7921_dev *dev = data; 26 27 *val = dev->fw_debug; 28 29 return 0; 30 } 31 32 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7921_fw_debug_get, 33 mt7921_fw_debug_set, "%lld\n"); 34 35 static void 36 mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy, 37 struct seq_file *file) 38 { 39 struct mt7921_dev *dev = file->private; 40 int bound[15], range[4], i; 41 42 if (!phy) 43 return; 44 45 /* Tx ampdu stat */ 46 for (i = 0; i < ARRAY_SIZE(range); i++) 47 range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i)); 48 49 for (i = 0; i < ARRAY_SIZE(bound); i++) 50 bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1; 51 52 seq_printf(file, "\nPhy0\n"); 53 54 seq_printf(file, "Length: %8d | ", bound[0]); 55 for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) 56 seq_printf(file, "%3d %3d | ", bound[i] + 1, bound[i + 1]); 57 58 seq_puts(file, "\nCount: "); 59 for (i = 0; i < ARRAY_SIZE(bound); i++) 60 seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); 61 seq_puts(file, "\n"); 62 63 seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); 64 } 65 66 static int 67 mt7921_tx_stats_show(struct seq_file *file, void *data) 68 { 69 struct mt7921_dev *dev = file->private; 70 int stat[8], i, n; 71 72 mt7921_ampdu_stat_read_phy(&dev->phy, file); 73 74 /* Tx amsdu info */ 75 seq_puts(file, "Tx MSDU stat:\n"); 76 for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { 77 stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); 78 n += stat[i]; 79 } 80 81 for (i = 0; i < ARRAY_SIZE(stat); i++) { 82 seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ", 83 i + 1, stat[i]); 84 if (n != 0) 85 seq_printf(file, "(%d%%)\n", stat[i] * 100 / n); 86 else 87 seq_puts(file, "\n"); 88 } 89 90 return 0; 91 } 92 93 DEFINE_SHOW_ATTRIBUTE(mt7921_tx_stats); 94 95 static int 96 mt7921_queues_acq(struct seq_file *s, void *data) 97 { 98 struct mt7921_dev *dev = dev_get_drvdata(s->private); 99 int i; 100 101 for (i = 0; i < 16; i++) { 102 int j, acs = i / 4, index = i % 4; 103 u32 ctrl, val, qlen = 0; 104 105 val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); 106 ctrl = BIT(31) | BIT(15) | (acs << 8); 107 108 for (j = 0; j < 32; j++) { 109 if (val & BIT(j)) 110 continue; 111 112 mt76_wr(dev, MT_PLE_FL_Q0_CTRL, 113 ctrl | (j + (index << 5))); 114 qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, 115 GENMASK(11, 0)); 116 } 117 seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); 118 } 119 120 return 0; 121 } 122 123 static int 124 mt7921_queues_read(struct seq_file *s, void *data) 125 { 126 struct mt7921_dev *dev = dev_get_drvdata(s->private); 127 struct { 128 struct mt76_queue *q; 129 char *queue; 130 } queue_map[] = { 131 { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" }, 132 { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" }, 133 { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" }, 134 }; 135 int i; 136 137 for (i = 0; i < ARRAY_SIZE(queue_map); i++) { 138 struct mt76_queue *q = queue_map[i].q; 139 140 if (!q) 141 continue; 142 143 seq_printf(s, 144 "%s: queued=%d head=%d tail=%d\n", 145 queue_map[i].queue, q->queued, q->head, 146 q->tail); 147 } 148 149 return 0; 150 } 151 152 static void 153 mt7921_seq_puts_array(struct seq_file *file, const char *str, 154 s8 *val, int len) 155 { 156 int i; 157 158 seq_printf(file, "%-16s:", str); 159 for (i = 0; i < len; i++) 160 if (val[i] == 127) 161 seq_printf(file, " %6s", "N.A"); 162 else 163 seq_printf(file, " %6d", val[i]); 164 seq_puts(file, "\n"); 165 } 166 167 #define mt7921_print_txpwr_entry(prefix, rate) \ 168 ({ \ 169 mt7921_seq_puts_array(s, #prefix " (user)", \ 170 txpwr.data[TXPWR_USER].rate, \ 171 ARRAY_SIZE(txpwr.data[TXPWR_USER].rate)); \ 172 mt7921_seq_puts_array(s, #prefix " (eeprom)", \ 173 txpwr.data[TXPWR_EEPROM].rate, \ 174 ARRAY_SIZE(txpwr.data[TXPWR_EEPROM].rate)); \ 175 mt7921_seq_puts_array(s, #prefix " (tmac)", \ 176 txpwr.data[TXPWR_MAC].rate, \ 177 ARRAY_SIZE(txpwr.data[TXPWR_MAC].rate)); \ 178 }) 179 180 static int 181 mt7921_txpwr(struct seq_file *s, void *data) 182 { 183 struct mt7921_dev *dev = dev_get_drvdata(s->private); 184 struct mt7921_txpwr txpwr; 185 int ret; 186 187 mt7921_mutex_acquire(dev); 188 ret = mt7921_get_txpwr_info(dev, &txpwr); 189 mt7921_mutex_release(dev); 190 191 if (ret) 192 return ret; 193 194 seq_printf(s, "Tx power table (channel %d)\n", txpwr.ch); 195 seq_printf(s, "%-16s %6s %6s %6s %6s\n", 196 " ", "1m", "2m", "5m", "11m"); 197 mt7921_print_txpwr_entry(CCK, cck); 198 199 seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", 200 " ", "6m", "9m", "12m", "18m", "24m", "36m", 201 "48m", "54m"); 202 mt7921_print_txpwr_entry(OFDM, ofdm); 203 204 seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", 205 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", 206 "mcs6", "mcs7"); 207 mt7921_print_txpwr_entry(HT20, ht20); 208 209 seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", 210 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", 211 "mcs6", "mcs7", "mcs32"); 212 mt7921_print_txpwr_entry(HT40, ht40); 213 214 seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", 215 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", 216 "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11"); 217 mt7921_print_txpwr_entry(VHT20, vht20); 218 mt7921_print_txpwr_entry(VHT40, vht40); 219 mt7921_print_txpwr_entry(VHT80, vht80); 220 mt7921_print_txpwr_entry(VHT160, vht160); 221 mt7921_print_txpwr_entry(HE26, he26); 222 mt7921_print_txpwr_entry(HE52, he52); 223 mt7921_print_txpwr_entry(HE106, he106); 224 mt7921_print_txpwr_entry(HE242, he242); 225 mt7921_print_txpwr_entry(HE484, he484); 226 mt7921_print_txpwr_entry(HE996, he996); 227 mt7921_print_txpwr_entry(HE996x2, he996x2); 228 229 return 0; 230 } 231 232 static int 233 mt7921_pm_set(void *data, u64 val) 234 { 235 struct mt7921_dev *dev = data; 236 struct mt76_connac_pm *pm = &dev->pm; 237 struct mt76_phy *mphy = dev->phy.mt76; 238 239 if (val == pm->enable) 240 return 0; 241 242 mt7921_mutex_acquire(dev); 243 244 if (!pm->enable) { 245 pm->stats.last_wake_event = jiffies; 246 pm->stats.last_doze_event = jiffies; 247 } 248 pm->enable = val; 249 250 ieee80211_iterate_active_interfaces(mphy->hw, 251 IEEE80211_IFACE_ITER_RESUME_ALL, 252 mt7921_pm_interface_iter, mphy->priv); 253 254 mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); 255 256 mt7921_mutex_release(dev); 257 258 return 0; 259 } 260 261 static int 262 mt7921_pm_get(void *data, u64 *val) 263 { 264 struct mt7921_dev *dev = data; 265 266 *val = dev->pm.enable; 267 268 return 0; 269 } 270 271 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n"); 272 273 static int 274 mt7921_deep_sleep_set(void *data, u64 val) 275 { 276 struct mt7921_dev *dev = data; 277 struct mt76_connac_pm *pm = &dev->pm; 278 bool enable = !!val; 279 280 mt7921_mutex_acquire(dev); 281 if (pm->ds_enable != enable) { 282 mt76_connac_mcu_set_deep_sleep(&dev->mt76, enable); 283 pm->ds_enable = enable; 284 } 285 mt7921_mutex_release(dev); 286 287 return 0; 288 } 289 290 static int 291 mt7921_deep_sleep_get(void *data, u64 *val) 292 { 293 struct mt7921_dev *dev = data; 294 295 *val = dev->pm.ds_enable; 296 297 return 0; 298 } 299 300 DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, mt7921_deep_sleep_get, 301 mt7921_deep_sleep_set, "%lld\n"); 302 303 static int 304 mt7921_pm_stats(struct seq_file *s, void *data) 305 { 306 struct mt7921_dev *dev = dev_get_drvdata(s->private); 307 struct mt76_connac_pm *pm = &dev->pm; 308 309 unsigned long awake_time = pm->stats.awake_time; 310 unsigned long doze_time = pm->stats.doze_time; 311 312 if (!test_bit(MT76_STATE_PM, &dev->mphy.state)) 313 awake_time += jiffies - pm->stats.last_wake_event; 314 else 315 doze_time += jiffies - pm->stats.last_doze_event; 316 317 seq_printf(s, "awake time: %14u\ndoze time: %15u\n", 318 jiffies_to_msecs(awake_time), 319 jiffies_to_msecs(doze_time)); 320 321 seq_printf(s, "low power wakes: %9d\n", pm->stats.lp_wake); 322 323 return 0; 324 } 325 326 static int 327 mt7921_pm_idle_timeout_set(void *data, u64 val) 328 { 329 struct mt7921_dev *dev = data; 330 331 dev->pm.idle_timeout = msecs_to_jiffies(val); 332 333 return 0; 334 } 335 336 static int 337 mt7921_pm_idle_timeout_get(void *data, u64 *val) 338 { 339 struct mt7921_dev *dev = data; 340 341 *val = jiffies_to_msecs(dev->pm.idle_timeout); 342 343 return 0; 344 } 345 346 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get, 347 mt7921_pm_idle_timeout_set, "%lld\n"); 348 349 static int mt7921_chip_reset(void *data, u64 val) 350 { 351 struct mt7921_dev *dev = data; 352 int ret = 0; 353 354 switch (val) { 355 case 1: 356 /* Reset wifisys directly. */ 357 mt7921_reset(&dev->mt76); 358 break; 359 default: 360 /* Collect the core dump before reset wifisys. */ 361 mt7921_mutex_acquire(dev); 362 ret = mt76_connac_mcu_chip_config(&dev->mt76); 363 mt7921_mutex_release(dev); 364 break; 365 } 366 367 return ret; 368 } 369 370 DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7921_chip_reset, "%lld\n"); 371 372 int mt7921_init_debugfs(struct mt7921_dev *dev) 373 { 374 struct dentry *dir; 375 376 dir = mt76_register_debugfs(&dev->mt76); 377 if (!dir) 378 return -ENOMEM; 379 380 debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, 381 mt7921_queues_read); 382 debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, 383 mt7921_queues_acq); 384 debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir, 385 mt7921_txpwr); 386 debugfs_create_file("tx_stats", 0400, dir, dev, &mt7921_tx_stats_fops); 387 debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); 388 debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm); 389 debugfs_create_file("idle-timeout", 0600, dir, dev, 390 &fops_pm_idle_timeout); 391 debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset); 392 debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir, 393 mt7921_pm_stats); 394 debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds); 395 396 return 0; 397 } 398