162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/relay.h> 562306a36Sopenharmony_ci#include "mt7915.h" 662306a36Sopenharmony_ci#include "eeprom.h" 762306a36Sopenharmony_ci#include "mcu.h" 862306a36Sopenharmony_ci#include "mac.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define FW_BIN_LOG_MAGIC 0x44e98caf 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/** global debugfs **/ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistruct hw_queue_map { 1562306a36Sopenharmony_ci const char *name; 1662306a36Sopenharmony_ci u8 index; 1762306a36Sopenharmony_ci u8 pid; 1862306a36Sopenharmony_ci u8 qid; 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int 2262306a36Sopenharmony_cimt7915_implicit_txbf_set(void *data, u64 val) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct mt7915_dev *dev = data; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* The existing connected stations shall reconnect to apply 2762306a36Sopenharmony_ci * new implicit txbf configuration. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci dev->ibf = !!val; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int 3562306a36Sopenharmony_cimt7915_implicit_txbf_get(void *data, u64 *val) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct mt7915_dev *dev = data; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci *val = dev->ibf; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get, 4562306a36Sopenharmony_ci mt7915_implicit_txbf_set, "%lld\n"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* test knob of system error recovery */ 4862306a36Sopenharmony_cistatic ssize_t 4962306a36Sopenharmony_cimt7915_sys_recovery_set(struct file *file, const char __user *user_buf, 5062306a36Sopenharmony_ci size_t count, loff_t *ppos) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct mt7915_phy *phy = file->private_data; 5362306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 5462306a36Sopenharmony_ci bool band = phy->mt76->band_idx; 5562306a36Sopenharmony_ci char buf[16]; 5662306a36Sopenharmony_ci int ret = 0; 5762306a36Sopenharmony_ci u16 val; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (count >= sizeof(buf)) 6062306a36Sopenharmony_ci return -EINVAL; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (copy_from_user(buf, user_buf, count)) 6362306a36Sopenharmony_ci return -EFAULT; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (count && buf[count - 1] == '\n') 6662306a36Sopenharmony_ci buf[count - 1] = '\0'; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci buf[count] = '\0'; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (kstrtou16(buf, 0, &val)) 7162306a36Sopenharmony_ci return -EINVAL; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci switch (val) { 7462306a36Sopenharmony_ci /* 7562306a36Sopenharmony_ci * 0: grab firmware current SER state. 7662306a36Sopenharmony_ci * 1: trigger & enable system error L1 recovery. 7762306a36Sopenharmony_ci * 2: trigger & enable system error L2 recovery. 7862306a36Sopenharmony_ci * 3: trigger & enable system error L3 rx abort. 7962306a36Sopenharmony_ci * 4: trigger & enable system error L3 tx abort 8062306a36Sopenharmony_ci * 5: trigger & enable system error L3 tx disable. 8162306a36Sopenharmony_ci * 6: trigger & enable system error L3 bf recovery. 8262306a36Sopenharmony_ci * 7: trigger & enable system error full recovery. 8362306a36Sopenharmony_ci * 8: trigger firmware crash. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci case SER_QUERY: 8662306a36Sopenharmony_ci ret = mt7915_mcu_set_ser(dev, 0, 0, band); 8762306a36Sopenharmony_ci break; 8862306a36Sopenharmony_ci case SER_SET_RECOVER_L1: 8962306a36Sopenharmony_ci case SER_SET_RECOVER_L2: 9062306a36Sopenharmony_ci case SER_SET_RECOVER_L3_RX_ABORT: 9162306a36Sopenharmony_ci case SER_SET_RECOVER_L3_TX_ABORT: 9262306a36Sopenharmony_ci case SER_SET_RECOVER_L3_TX_DISABLE: 9362306a36Sopenharmony_ci case SER_SET_RECOVER_L3_BF: 9462306a36Sopenharmony_ci ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), band); 9562306a36Sopenharmony_ci if (ret) 9662306a36Sopenharmony_ci return ret; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, band); 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* enable full chip reset */ 10262306a36Sopenharmony_ci case SER_SET_RECOVER_FULL: 10362306a36Sopenharmony_ci mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); 10462306a36Sopenharmony_ci ret = mt7915_mcu_set_ser(dev, 1, 3, band); 10562306a36Sopenharmony_ci if (ret) 10662306a36Sopenharmony_ci return ret; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci dev->recovery.state |= MT_MCU_CMD_WDT_MASK; 10962306a36Sopenharmony_ci mt7915_reset(dev); 11062306a36Sopenharmony_ci break; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* WARNING: trigger firmware crash */ 11362306a36Sopenharmony_ci case SER_SET_SYSTEM_ASSERT: 11462306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18)); 11562306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18)); 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci default: 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return ret ? ret : count; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic ssize_t 12562306a36Sopenharmony_cimt7915_sys_recovery_get(struct file *file, char __user *user_buf, 12662306a36Sopenharmony_ci size_t count, loff_t *ppos) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct mt7915_phy *phy = file->private_data; 12962306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 13062306a36Sopenharmony_ci char *buff; 13162306a36Sopenharmony_ci int desc = 0; 13262306a36Sopenharmony_ci ssize_t ret; 13362306a36Sopenharmony_ci static const size_t bufsz = 1024; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci buff = kmalloc(bufsz, GFP_KERNEL); 13662306a36Sopenharmony_ci if (!buff) 13762306a36Sopenharmony_ci return -ENOMEM; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* HELP */ 14062306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 14162306a36Sopenharmony_ci "Please echo the correct value ...\n"); 14262306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 14362306a36Sopenharmony_ci "0: grab firmware transient SER state\n"); 14462306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 14562306a36Sopenharmony_ci "1: trigger system error L1 recovery\n"); 14662306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 14762306a36Sopenharmony_ci "2: trigger system error L2 recovery\n"); 14862306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 14962306a36Sopenharmony_ci "3: trigger system error L3 rx abort\n"); 15062306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 15162306a36Sopenharmony_ci "4: trigger system error L3 tx abort\n"); 15262306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 15362306a36Sopenharmony_ci "5: trigger system error L3 tx disable\n"); 15462306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 15562306a36Sopenharmony_ci "6: trigger system error L3 bf recovery\n"); 15662306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 15762306a36Sopenharmony_ci "7: trigger system error full recovery\n"); 15862306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 15962306a36Sopenharmony_ci "8: trigger firmware crash\n"); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* SER statistics */ 16262306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 16362306a36Sopenharmony_ci "\nlet's dump firmware SER statistics...\n"); 16462306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 16562306a36Sopenharmony_ci "::E R , SER_STATUS = 0x%08x\n", 16662306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_SER_STATS)); 16762306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 16862306a36Sopenharmony_ci "::E R , SER_PLE_ERR = 0x%08x\n", 16962306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_PLE_STATS)); 17062306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 17162306a36Sopenharmony_ci "::E R , SER_PLE_ERR_1 = 0x%08x\n", 17262306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_PLE1_STATS)); 17362306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 17462306a36Sopenharmony_ci "::E R , SER_PLE_ERR_AMSDU = 0x%08x\n", 17562306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS)); 17662306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 17762306a36Sopenharmony_ci "::E R , SER_PSE_ERR = 0x%08x\n", 17862306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_PSE_STATS)); 17962306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 18062306a36Sopenharmony_ci "::E R , SER_PSE_ERR_1 = 0x%08x\n", 18162306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_PSE1_STATS)); 18262306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 18362306a36Sopenharmony_ci "::E R , SER_LMAC_WISR6_B0 = 0x%08x\n", 18462306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS)); 18562306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 18662306a36Sopenharmony_ci "::E R , SER_LMAC_WISR6_B1 = 0x%08x\n", 18762306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS)); 18862306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 18962306a36Sopenharmony_ci "::E R , SER_LMAC_WISR7_B0 = 0x%08x\n", 19062306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS)); 19162306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 19262306a36Sopenharmony_ci "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n", 19362306a36Sopenharmony_ci mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS)); 19462306a36Sopenharmony_ci desc += scnprintf(buff + desc, bufsz - desc, 19562306a36Sopenharmony_ci "\nSYS_RESET_COUNT: WM %d, WA %d\n", 19662306a36Sopenharmony_ci dev->recovery.wm_reset_count, 19762306a36Sopenharmony_ci dev->recovery.wa_reset_count); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); 20062306a36Sopenharmony_ci kfree(buff); 20162306a36Sopenharmony_ci return ret; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic const struct file_operations mt7915_sys_recovery_ops = { 20562306a36Sopenharmony_ci .write = mt7915_sys_recovery_set, 20662306a36Sopenharmony_ci .read = mt7915_sys_recovery_get, 20762306a36Sopenharmony_ci .open = simple_open, 20862306a36Sopenharmony_ci .llseek = default_llseek, 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int 21262306a36Sopenharmony_cimt7915_radar_trigger(void *data, u64 val) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct mt7915_dev *dev = data; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (val > MT_RX_SEL2) 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE, 22062306a36Sopenharmony_ci val, 0, 0); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, 22462306a36Sopenharmony_ci mt7915_radar_trigger, "%lld\n"); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int 22762306a36Sopenharmony_cimt7915_muru_debug_set(void *data, u64 val) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct mt7915_dev *dev = data; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci dev->muru_debug = val; 23262306a36Sopenharmony_ci mt7915_mcu_muru_debug_set(dev, dev->muru_debug); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int 23862306a36Sopenharmony_cimt7915_muru_debug_get(void *data, u64 *val) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct mt7915_dev *dev = data; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci *val = dev->muru_debug; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get, 24862306a36Sopenharmony_ci mt7915_muru_debug_set, "%lld\n"); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int mt7915_muru_stats_show(struct seq_file *file, void *data) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct mt7915_phy *phy = file->private; 25362306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 25462306a36Sopenharmony_ci static const char * const dl_non_he_type[] = { 25562306a36Sopenharmony_ci "CCK", "OFDM", "HT MIX", "HT GF", 25662306a36Sopenharmony_ci "VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU" 25762306a36Sopenharmony_ci }; 25862306a36Sopenharmony_ci static const char * const dl_he_type[] = { 25962306a36Sopenharmony_ci "HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU", 26062306a36Sopenharmony_ci "HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", 26162306a36Sopenharmony_ci "HE >16RU" 26262306a36Sopenharmony_ci }; 26362306a36Sopenharmony_ci static const char * const ul_he_type[] = { 26462306a36Sopenharmony_ci "HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU", 26562306a36Sopenharmony_ci "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU" 26662306a36Sopenharmony_ci }; 26762306a36Sopenharmony_ci int ret, i; 26862306a36Sopenharmony_ci u64 total_ppdu_cnt, sub_total_cnt; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (!dev->muru_debug) { 27162306a36Sopenharmony_ci seq_puts(file, "Please enable muru_debug first.\n"); 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ret = mt7915_mcu_muru_debug_get(phy); 27862306a36Sopenharmony_ci if (ret) 27962306a36Sopenharmony_ci goto exit; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Non-HE Downlink*/ 28262306a36Sopenharmony_ci seq_puts(file, "[Non-HE]\nDownlink\nData Type: "); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci for (i = 0; i < 5; i++) 28562306a36Sopenharmony_ci seq_printf(file, "%8s | ", dl_non_he_type[i]); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci seq_puts(file, "\nTotal Count:"); 28862306a36Sopenharmony_ci seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ", 28962306a36Sopenharmony_ci phy->mib.dl_cck_cnt, 29062306a36Sopenharmony_ci phy->mib.dl_ofdm_cnt, 29162306a36Sopenharmony_ci phy->mib.dl_htmix_cnt, 29262306a36Sopenharmony_ci phy->mib.dl_htgf_cnt, 29362306a36Sopenharmony_ci phy->mib.dl_vht_su_cnt); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci seq_puts(file, "\nDownlink MU-MIMO\nData Type: "); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci for (i = 5; i < 8; i++) 29862306a36Sopenharmony_ci seq_printf(file, "%8s | ", dl_non_he_type[i]); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci seq_puts(file, "\nTotal Count:"); 30162306a36Sopenharmony_ci seq_printf(file, "%8u | %8u | %8u | ", 30262306a36Sopenharmony_ci phy->mib.dl_vht_2mu_cnt, 30362306a36Sopenharmony_ci phy->mib.dl_vht_3mu_cnt, 30462306a36Sopenharmony_ci phy->mib.dl_vht_4mu_cnt); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci sub_total_cnt = phy->mib.dl_vht_2mu_cnt + 30762306a36Sopenharmony_ci phy->mib.dl_vht_3mu_cnt + 30862306a36Sopenharmony_ci phy->mib.dl_vht_4mu_cnt; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld", 31162306a36Sopenharmony_ci sub_total_cnt); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci total_ppdu_cnt = sub_total_cnt + 31462306a36Sopenharmony_ci phy->mib.dl_cck_cnt + 31562306a36Sopenharmony_ci phy->mib.dl_ofdm_cnt + 31662306a36Sopenharmony_ci phy->mib.dl_htmix_cnt + 31762306a36Sopenharmony_ci phy->mib.dl_htgf_cnt + 31862306a36Sopenharmony_ci phy->mib.dl_vht_su_cnt; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* HE Downlink */ 32362306a36Sopenharmony_ci seq_puts(file, "\n\n[HE]\nDownlink\nData Type: "); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci for (i = 0; i < 2; i++) 32662306a36Sopenharmony_ci seq_printf(file, "%8s | ", dl_he_type[i]); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci seq_puts(file, "\nTotal Count:"); 32962306a36Sopenharmony_ci seq_printf(file, "%8u | %8u | ", 33062306a36Sopenharmony_ci phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci seq_puts(file, "\nDownlink MU-MIMO\nData Type: "); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci for (i = 2; i < 5; i++) 33562306a36Sopenharmony_ci seq_printf(file, "%8s | ", dl_he_type[i]); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci seq_puts(file, "\nTotal Count:"); 33862306a36Sopenharmony_ci seq_printf(file, "%8u | %8u | %8u | ", 33962306a36Sopenharmony_ci phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt, 34062306a36Sopenharmony_ci phy->mib.dl_he_4mu_cnt); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci seq_puts(file, "\nDownlink OFDMA\nData Type: "); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci for (i = 5; i < 11; i++) 34562306a36Sopenharmony_ci seq_printf(file, "%8s | ", dl_he_type[i]); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci seq_puts(file, "\nTotal Count:"); 34862306a36Sopenharmony_ci seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ", 34962306a36Sopenharmony_ci phy->mib.dl_he_2ru_cnt, 35062306a36Sopenharmony_ci phy->mib.dl_he_3ru_cnt, 35162306a36Sopenharmony_ci phy->mib.dl_he_4ru_cnt, 35262306a36Sopenharmony_ci phy->mib.dl_he_5to8ru_cnt, 35362306a36Sopenharmony_ci phy->mib.dl_he_9to16ru_cnt, 35462306a36Sopenharmony_ci phy->mib.dl_he_gtr16ru_cnt); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci sub_total_cnt = phy->mib.dl_he_2mu_cnt + 35762306a36Sopenharmony_ci phy->mib.dl_he_3mu_cnt + 35862306a36Sopenharmony_ci phy->mib.dl_he_4mu_cnt; 35962306a36Sopenharmony_ci total_ppdu_cnt = sub_total_cnt; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld", 36262306a36Sopenharmony_ci sub_total_cnt); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci sub_total_cnt = phy->mib.dl_he_2ru_cnt + 36562306a36Sopenharmony_ci phy->mib.dl_he_3ru_cnt + 36662306a36Sopenharmony_ci phy->mib.dl_he_4ru_cnt + 36762306a36Sopenharmony_ci phy->mib.dl_he_5to8ru_cnt + 36862306a36Sopenharmony_ci phy->mib.dl_he_9to16ru_cnt + 36962306a36Sopenharmony_ci phy->mib.dl_he_gtr16ru_cnt; 37062306a36Sopenharmony_ci total_ppdu_cnt += sub_total_cnt; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld", 37362306a36Sopenharmony_ci sub_total_cnt); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci total_ppdu_cnt += phy->mib.dl_he_su_cnt + phy->mib.dl_he_ext_su_cnt; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* HE Uplink */ 38062306a36Sopenharmony_ci seq_puts(file, "\n\nUplink"); 38162306a36Sopenharmony_ci seq_puts(file, "\nTrigger-based Uplink MU-MIMO\nData Type: "); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci for (i = 0; i < 3; i++) 38462306a36Sopenharmony_ci seq_printf(file, "%8s | ", ul_he_type[i]); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci seq_puts(file, "\nTotal Count:"); 38762306a36Sopenharmony_ci seq_printf(file, "%8u | %8u | %8u | ", 38862306a36Sopenharmony_ci phy->mib.ul_hetrig_2mu_cnt, 38962306a36Sopenharmony_ci phy->mib.ul_hetrig_3mu_cnt, 39062306a36Sopenharmony_ci phy->mib.ul_hetrig_4mu_cnt); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type: "); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci for (i = 3; i < 10; i++) 39562306a36Sopenharmony_ci seq_printf(file, "%8s | ", ul_he_type[i]); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci seq_puts(file, "\nTotal Count:"); 39862306a36Sopenharmony_ci seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u | %7u | ", 39962306a36Sopenharmony_ci phy->mib.ul_hetrig_su_cnt, 40062306a36Sopenharmony_ci phy->mib.ul_hetrig_2ru_cnt, 40162306a36Sopenharmony_ci phy->mib.ul_hetrig_3ru_cnt, 40262306a36Sopenharmony_ci phy->mib.ul_hetrig_4ru_cnt, 40362306a36Sopenharmony_ci phy->mib.ul_hetrig_5to8ru_cnt, 40462306a36Sopenharmony_ci phy->mib.ul_hetrig_9to16ru_cnt, 40562306a36Sopenharmony_ci phy->mib.ul_hetrig_gtr16ru_cnt); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci sub_total_cnt = phy->mib.ul_hetrig_2mu_cnt + 40862306a36Sopenharmony_ci phy->mib.ul_hetrig_3mu_cnt + 40962306a36Sopenharmony_ci phy->mib.ul_hetrig_4mu_cnt; 41062306a36Sopenharmony_ci total_ppdu_cnt = sub_total_cnt; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld", 41362306a36Sopenharmony_ci sub_total_cnt); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci sub_total_cnt = phy->mib.ul_hetrig_2ru_cnt + 41662306a36Sopenharmony_ci phy->mib.ul_hetrig_3ru_cnt + 41762306a36Sopenharmony_ci phy->mib.ul_hetrig_4ru_cnt + 41862306a36Sopenharmony_ci phy->mib.ul_hetrig_5to8ru_cnt + 41962306a36Sopenharmony_ci phy->mib.ul_hetrig_9to16ru_cnt + 42062306a36Sopenharmony_ci phy->mib.ul_hetrig_gtr16ru_cnt; 42162306a36Sopenharmony_ci total_ppdu_cnt += sub_total_cnt; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld", 42462306a36Sopenharmony_ci sub_total_cnt); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ciexit: 43162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return ret; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int 43862306a36Sopenharmony_cimt7915_rdd_monitor(struct seq_file *s, void *data) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct mt7915_dev *dev = dev_get_drvdata(s->private); 44162306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = &dev->rdd2_chandef; 44262306a36Sopenharmony_ci const char *bw; 44362306a36Sopenharmony_ci int ret = 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!cfg80211_chandef_valid(chandef)) { 44862306a36Sopenharmony_ci ret = -EINVAL; 44962306a36Sopenharmony_ci goto out; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (!dev->rdd2_phy) { 45362306a36Sopenharmony_ci seq_puts(s, "not running\n"); 45462306a36Sopenharmony_ci goto out; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci switch (chandef->width) { 45862306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 45962306a36Sopenharmony_ci bw = "40"; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 46262306a36Sopenharmony_ci bw = "80"; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 46562306a36Sopenharmony_ci bw = "160"; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 46862306a36Sopenharmony_ci bw = "80P80"; 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci default: 47162306a36Sopenharmony_ci bw = "20"; 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n", 47662306a36Sopenharmony_ci chandef->chan->hw_value, chandef->chan->center_freq, 47762306a36Sopenharmony_ci bw, chandef->center_freq1); 47862306a36Sopenharmony_ciout: 47962306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return ret; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int 48562306a36Sopenharmony_cimt7915_fw_debug_wm_set(void *data, u64 val) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct mt7915_dev *dev = data; 48862306a36Sopenharmony_ci enum { 48962306a36Sopenharmony_ci DEBUG_TXCMD = 62, 49062306a36Sopenharmony_ci DEBUG_CMD_RPT_TX, 49162306a36Sopenharmony_ci DEBUG_CMD_RPT_TRIG, 49262306a36Sopenharmony_ci DEBUG_SPL, 49362306a36Sopenharmony_ci DEBUG_RPT_RX, 49462306a36Sopenharmony_ci } debug; 49562306a36Sopenharmony_ci bool tx, rx, en; 49662306a36Sopenharmony_ci int ret; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (dev->fw.debug_bin) 50162306a36Sopenharmony_ci val = 16; 50262306a36Sopenharmony_ci else 50362306a36Sopenharmony_ci val = dev->fw.debug_wm; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1)); 50662306a36Sopenharmony_ci rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2)); 50762306a36Sopenharmony_ci en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0)); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val); 51062306a36Sopenharmony_ci if (ret) 51162306a36Sopenharmony_ci goto out; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) { 51462306a36Sopenharmony_ci if (debug == DEBUG_RPT_RX) 51562306a36Sopenharmony_ci val = en && rx; 51662306a36Sopenharmony_ci else 51762306a36Sopenharmony_ci val = en && tx; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val); 52062306a36Sopenharmony_ci if (ret) 52162306a36Sopenharmony_ci goto out; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* WM CPU info record control */ 52562306a36Sopenharmony_ci mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0)); 52662306a36Sopenharmony_ci mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | !dev->fw.debug_wm); 52762306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5)); 52862306a36Sopenharmony_ci mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5)); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciout: 53162306a36Sopenharmony_ci if (ret) 53262306a36Sopenharmony_ci dev->fw.debug_wm = 0; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return ret; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int 53862306a36Sopenharmony_cimt7915_fw_debug_wm_get(void *data, u64 *val) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct mt7915_dev *dev = data; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci *val = dev->fw.debug_wm; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get, 54862306a36Sopenharmony_ci mt7915_fw_debug_wm_set, "%lld\n"); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic int 55162306a36Sopenharmony_cimt7915_fw_debug_wa_set(void *data, u64 val) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct mt7915_dev *dev = data; 55462306a36Sopenharmony_ci int ret; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw.debug_wa); 55962306a36Sopenharmony_ci if (ret) 56062306a36Sopenharmony_ci goto out; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), 56362306a36Sopenharmony_ci MCU_WA_PARAM_PDMA_RX, !!dev->fw.debug_wa, 0); 56462306a36Sopenharmony_ciout: 56562306a36Sopenharmony_ci if (ret) 56662306a36Sopenharmony_ci dev->fw.debug_wa = 0; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return ret; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int 57262306a36Sopenharmony_cimt7915_fw_debug_wa_get(void *data, u64 *val) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct mt7915_dev *dev = data; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci *val = dev->fw.debug_wa; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci return 0; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get, 58262306a36Sopenharmony_ci mt7915_fw_debug_wa_set, "%lld\n"); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic struct dentry * 58562306a36Sopenharmony_cicreate_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode, 58662306a36Sopenharmony_ci struct rchan_buf *buf, int *is_global) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct dentry *f; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci f = debugfs_create_file("fwlog_data", mode, parent, buf, 59162306a36Sopenharmony_ci &relay_file_operations); 59262306a36Sopenharmony_ci if (IS_ERR(f)) 59362306a36Sopenharmony_ci return NULL; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci *is_global = 1; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return f; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int 60162306a36Sopenharmony_ciremove_buf_file_cb(struct dentry *f) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci debugfs_remove(f); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int 60962306a36Sopenharmony_cimt7915_fw_debug_bin_set(void *data, u64 val) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci static struct rchan_callbacks relay_cb = { 61262306a36Sopenharmony_ci .create_buf_file = create_buf_file_cb, 61362306a36Sopenharmony_ci .remove_buf_file = remove_buf_file_cb, 61462306a36Sopenharmony_ci }; 61562306a36Sopenharmony_ci struct mt7915_dev *dev = data; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (!dev->relay_fwlog) 61862306a36Sopenharmony_ci dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir, 61962306a36Sopenharmony_ci 1500, 512, &relay_cb, NULL); 62062306a36Sopenharmony_ci if (!dev->relay_fwlog) 62162306a36Sopenharmony_ci return -ENOMEM; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci dev->fw.debug_bin = val; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci relay_reset(dev->relay_fwlog); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci return mt7915_fw_debug_wm_set(dev, dev->fw.debug_wm); 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic int 63162306a36Sopenharmony_cimt7915_fw_debug_bin_get(void *data, u64 *val) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct mt7915_dev *dev = data; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci *val = dev->fw.debug_bin; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get, 64162306a36Sopenharmony_ci mt7915_fw_debug_bin_set, "%lld\n"); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int 64462306a36Sopenharmony_cimt7915_fw_util_wm_show(struct seq_file *file, void *data) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct mt7915_dev *dev = file->private; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC)); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (dev->fw.debug_wm) { 65162306a36Sopenharmony_ci seq_printf(file, "Busy: %u%% Peak busy: %u%%\n", 65262306a36Sopenharmony_ci mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT), 65362306a36Sopenharmony_ci mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT)); 65462306a36Sopenharmony_ci seq_printf(file, "Idle count: %u Peak idle count: %u\n", 65562306a36Sopenharmony_ci mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT), 65662306a36Sopenharmony_ci mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT)); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci return 0; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic int 66562306a36Sopenharmony_cimt7915_fw_util_wa_show(struct seq_file *file, void *data) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct mt7915_dev *dev = file->private; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WA_MCU_PC)); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (dev->fw.debug_wa) 67262306a36Sopenharmony_ci return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY), 67362306a36Sopenharmony_ci MCU_WA_PARAM_CPU_UTIL, 0, 0); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return 0; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic void 68162306a36Sopenharmony_cimt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, 68262306a36Sopenharmony_ci struct seq_file *file) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 68562306a36Sopenharmony_ci bool ext_phy = phy != &dev->phy; 68662306a36Sopenharmony_ci int bound[15], range[4], i; 68762306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Tx ampdu stat */ 69062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(range); i++) 69162306a36Sopenharmony_ci range[i] = mt76_rr(dev, MT_MIB_ARNG(band, i)); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bound); i++) 69462306a36Sopenharmony_ci bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, band); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci seq_printf(file, "Length: %8d | ", bound[0]); 69962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) 70062306a36Sopenharmony_ci seq_printf(file, "%3d -%3d | ", 70162306a36Sopenharmony_ci bound[i] + 1, bound[i + 1]); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci seq_puts(file, "\nCount: "); 70462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bound); i++) 70562306a36Sopenharmony_ci seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]); 70662306a36Sopenharmony_ci seq_puts(file, "\n"); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic void 71262306a36Sopenharmony_cimt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 71562306a36Sopenharmony_ci static const char * const bw[] = { 71662306a36Sopenharmony_ci "BW20", "BW40", "BW80", "BW160" 71762306a36Sopenharmony_ci }; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Tx Beamformer monitor */ 72062306a36Sopenharmony_ci seq_puts(s, "\nTx Beamformer applied PPDU counts: "); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci seq_printf(s, "iBF: %d, eBF: %d\n", 72362306a36Sopenharmony_ci mib->tx_bf_ibf_ppdu_cnt, 72462306a36Sopenharmony_ci mib->tx_bf_ebf_ppdu_cnt); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Tx Beamformer Rx feedback monitor */ 72762306a36Sopenharmony_ci seq_puts(s, "Tx Beamformer Rx feedback statistics: "); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", 73062306a36Sopenharmony_ci mib->tx_bf_rx_fb_all_cnt, 73162306a36Sopenharmony_ci mib->tx_bf_rx_fb_he_cnt, 73262306a36Sopenharmony_ci mib->tx_bf_rx_fb_vht_cnt, 73362306a36Sopenharmony_ci mib->tx_bf_rx_fb_ht_cnt); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci seq_printf(s, "%s, NC: %d, NR: %d\n", 73662306a36Sopenharmony_ci bw[mib->tx_bf_rx_fb_bw], 73762306a36Sopenharmony_ci mib->tx_bf_rx_fb_nc_cnt, 73862306a36Sopenharmony_ci mib->tx_bf_rx_fb_nr_cnt); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* Tx Beamformee Rx NDPA & Tx feedback report */ 74162306a36Sopenharmony_ci seq_printf(s, "Tx Beamformee successful feedback frames: %d\n", 74262306a36Sopenharmony_ci mib->tx_bf_fb_cpl_cnt); 74362306a36Sopenharmony_ci seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n", 74462306a36Sopenharmony_ci mib->tx_bf_fb_trig_cnt); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* Tx SU & MU counters */ 74762306a36Sopenharmony_ci seq_printf(s, "Tx multi-user Beamforming counts: %d\n", 74862306a36Sopenharmony_ci mib->tx_bf_cnt); 74962306a36Sopenharmony_ci seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt); 75062306a36Sopenharmony_ci seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", 75162306a36Sopenharmony_ci mib->tx_mu_acked_mpdu_cnt); 75262306a36Sopenharmony_ci seq_printf(s, "Tx single-user successful MPDU counts: %d\n", 75362306a36Sopenharmony_ci mib->tx_su_acked_mpdu_cnt); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci seq_puts(s, "\n"); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic int 75962306a36Sopenharmony_cimt7915_tx_stats_show(struct seq_file *file, void *data) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct mt7915_phy *phy = file->private; 76262306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 76362306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 76462306a36Sopenharmony_ci int i; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci mt7915_ampdu_stat_read_phy(phy, file); 76962306a36Sopenharmony_ci mt7915_mac_update_stats(phy); 77062306a36Sopenharmony_ci mt7915_txbf_stat_read_phy(phy, file); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Tx amsdu info */ 77362306a36Sopenharmony_ci seq_puts(file, "Tx MSDU statistics:\n"); 77462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { 77562306a36Sopenharmony_ci seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ", 77662306a36Sopenharmony_ci i + 1, mib->tx_amsdu[i]); 77762306a36Sopenharmony_ci if (mib->tx_amsdu_cnt) 77862306a36Sopenharmony_ci seq_printf(file, "(%3d%%)\n", 77962306a36Sopenharmony_ci mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt); 78062306a36Sopenharmony_ci else 78162306a36Sopenharmony_ci seq_puts(file, "\n"); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic void 79262306a36Sopenharmony_cimt7915_hw_queue_read(struct seq_file *s, u32 size, 79362306a36Sopenharmony_ci const struct hw_queue_map *map) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct mt7915_phy *phy = s->private; 79662306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 79762306a36Sopenharmony_ci u32 i, val; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci val = mt76_rr(dev, MT_FL_Q_EMPTY); 80062306a36Sopenharmony_ci for (i = 0; i < size; i++) { 80162306a36Sopenharmony_ci u32 ctrl, head, tail, queued; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (val & BIT(map[i].index)) 80462306a36Sopenharmony_ci continue; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24); 80762306a36Sopenharmony_ci mt76_wr(dev, MT_FL_Q0_CTRL, ctrl); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci head = mt76_get_field(dev, MT_FL_Q2_CTRL, 81062306a36Sopenharmony_ci GENMASK(11, 0)); 81162306a36Sopenharmony_ci tail = mt76_get_field(dev, MT_FL_Q2_CTRL, 81262306a36Sopenharmony_ci GENMASK(27, 16)); 81362306a36Sopenharmony_ci queued = mt76_get_field(dev, MT_FL_Q3_CTRL, 81462306a36Sopenharmony_ci GENMASK(11, 0)); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci seq_printf(s, "\t%s: ", map[i].name); 81762306a36Sopenharmony_ci seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n", 81862306a36Sopenharmony_ci queued, head, tail); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic void 82362306a36Sopenharmony_cimt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 82662306a36Sopenharmony_ci struct mt7915_dev *dev = msta->vif->phy->dev; 82762306a36Sopenharmony_ci struct seq_file *s = data; 82862306a36Sopenharmony_ci u8 ac; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci for (ac = 0; ac < 4; ac++) { 83162306a36Sopenharmony_ci u32 qlen, ctrl, val; 83262306a36Sopenharmony_ci u32 idx = msta->wcid.idx >> 5; 83362306a36Sopenharmony_ci u8 offs = msta->wcid.idx & GENMASK(4, 0); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ctrl = BIT(31) | BIT(11) | (ac << 24); 83662306a36Sopenharmony_ci val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx)); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (val & BIT(offs)) 83962306a36Sopenharmony_ci continue; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx); 84262306a36Sopenharmony_ci qlen = mt76_get_field(dev, MT_FL_Q3_CTRL, 84362306a36Sopenharmony_ci GENMASK(11, 0)); 84462306a36Sopenharmony_ci seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n", 84562306a36Sopenharmony_ci sta->addr, msta->wcid.idx, 84662306a36Sopenharmony_ci msta->vif->mt76.wmm_idx, ac, qlen); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int 85162306a36Sopenharmony_cimt7915_hw_queues_show(struct seq_file *file, void *data) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct mt7915_phy *phy = file->private; 85462306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 85562306a36Sopenharmony_ci static const struct hw_queue_map ple_queue_map[] = { 85662306a36Sopenharmony_ci { "CPU_Q0", 0, 1, MT_CTX0 }, 85762306a36Sopenharmony_ci { "CPU_Q1", 1, 1, MT_CTX0 + 1 }, 85862306a36Sopenharmony_ci { "CPU_Q2", 2, 1, MT_CTX0 + 2 }, 85962306a36Sopenharmony_ci { "CPU_Q3", 3, 1, MT_CTX0 + 3 }, 86062306a36Sopenharmony_ci { "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 }, 86162306a36Sopenharmony_ci { "BMC_Q0", 9, 2, MT_LMAC_BMC0 }, 86262306a36Sopenharmony_ci { "BCN_Q0", 10, 2, MT_LMAC_BCN0 }, 86362306a36Sopenharmony_ci { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 }, 86462306a36Sopenharmony_ci { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 }, 86562306a36Sopenharmony_ci { "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 }, 86662306a36Sopenharmony_ci { "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 }, 86762306a36Sopenharmony_ci { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 }, 86862306a36Sopenharmony_ci }; 86962306a36Sopenharmony_ci static const struct hw_queue_map pse_queue_map[] = { 87062306a36Sopenharmony_ci { "CPU Q0", 0, 1, MT_CTX0 }, 87162306a36Sopenharmony_ci { "CPU Q1", 1, 1, MT_CTX0 + 1 }, 87262306a36Sopenharmony_ci { "CPU Q2", 2, 1, MT_CTX0 + 2 }, 87362306a36Sopenharmony_ci { "CPU Q3", 3, 1, MT_CTX0 + 3 }, 87462306a36Sopenharmony_ci { "HIF_Q0", 8, 0, MT_HIF0 }, 87562306a36Sopenharmony_ci { "HIF_Q1", 9, 0, MT_HIF0 + 1 }, 87662306a36Sopenharmony_ci { "HIF_Q2", 10, 0, MT_HIF0 + 2 }, 87762306a36Sopenharmony_ci { "HIF_Q3", 11, 0, MT_HIF0 + 3 }, 87862306a36Sopenharmony_ci { "HIF_Q4", 12, 0, MT_HIF0 + 4 }, 87962306a36Sopenharmony_ci { "HIF_Q5", 13, 0, MT_HIF0 + 5 }, 88062306a36Sopenharmony_ci { "LMAC_Q", 16, 2, 0 }, 88162306a36Sopenharmony_ci { "MDP_TXQ", 17, 2, 1 }, 88262306a36Sopenharmony_ci { "MDP_RXQ", 18, 2, 2 }, 88362306a36Sopenharmony_ci { "SEC_TXQ", 19, 2, 3 }, 88462306a36Sopenharmony_ci { "SEC_RXQ", 20, 2, 4 }, 88562306a36Sopenharmony_ci }; 88662306a36Sopenharmony_ci u32 val, head, tail; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* ple queue */ 88962306a36Sopenharmony_ci val = mt76_rr(dev, MT_PLE_FREEPG_CNT); 89062306a36Sopenharmony_ci head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0)); 89162306a36Sopenharmony_ci tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16)); 89262306a36Sopenharmony_ci seq_puts(file, "PLE page info:\n"); 89362306a36Sopenharmony_ci seq_printf(file, 89462306a36Sopenharmony_ci "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n", 89562306a36Sopenharmony_ci val, head, tail); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP); 89862306a36Sopenharmony_ci head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0)); 89962306a36Sopenharmony_ci tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16)); 90062306a36Sopenharmony_ci seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", 90162306a36Sopenharmony_ci val, head, tail); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci seq_puts(file, "PLE non-empty queue info:\n"); 90462306a36Sopenharmony_ci mt7915_hw_queue_read(file, ARRAY_SIZE(ple_queue_map), 90562306a36Sopenharmony_ci &ple_queue_map[0]); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* iterate per-sta ple queue */ 90862306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(phy->mt76->hw, 90962306a36Sopenharmony_ci mt7915_sta_hw_queue_read, file); 91062306a36Sopenharmony_ci /* pse queue */ 91162306a36Sopenharmony_ci seq_puts(file, "PSE non-empty queue info:\n"); 91262306a36Sopenharmony_ci mt7915_hw_queue_read(file, ARRAY_SIZE(pse_queue_map), 91362306a36Sopenharmony_ci &pse_queue_map[0]); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic int 92162306a36Sopenharmony_cimt7915_xmit_queues_show(struct seq_file *file, void *data) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct mt7915_phy *phy = file->private; 92462306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 92562306a36Sopenharmony_ci struct { 92662306a36Sopenharmony_ci struct mt76_queue *q; 92762306a36Sopenharmony_ci char *queue; 92862306a36Sopenharmony_ci } queue_map[] = { 92962306a36Sopenharmony_ci { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" }, 93062306a36Sopenharmony_ci { dev->mt76.q_mcu[MT_MCUQ_WM], " MCUWM" }, 93162306a36Sopenharmony_ci { dev->mt76.q_mcu[MT_MCUQ_WA], " MCUWA" }, 93262306a36Sopenharmony_ci { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" }, 93362306a36Sopenharmony_ci }; 93462306a36Sopenharmony_ci int i; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci seq_puts(file, " queue | hw-queued | head | tail |\n"); 93762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(queue_map); i++) { 93862306a36Sopenharmony_ci struct mt76_queue *q = queue_map[i].q; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (!q) 94162306a36Sopenharmony_ci continue; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci seq_printf(file, " %s | %9d | %9d | %9d |\n", 94462306a36Sopenharmony_ci queue_map[i].queue, q->queued, q->head, 94562306a36Sopenharmony_ci q->tail); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return 0; 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci#define mt7915_txpower_puts(rate) \ 95462306a36Sopenharmony_ci({ \ 95562306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, "%-16s:", #rate " (TMAC)"); \ 95662306a36Sopenharmony_ci for (i = 0; i < mt7915_sku_group_len[SKU_##rate]; i++, offs++) \ 95762306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]); \ 95862306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, "\n"); \ 95962306a36Sopenharmony_ci}) 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci#define mt7915_txpower_sets(rate, pwr, flag) \ 96262306a36Sopenharmony_ci({ \ 96362306a36Sopenharmony_ci offs += len; \ 96462306a36Sopenharmony_ci len = mt7915_sku_group_len[rate]; \ 96562306a36Sopenharmony_ci if (mode == flag) { \ 96662306a36Sopenharmony_ci for (i = 0; i < len; i++) \ 96762306a36Sopenharmony_ci req.txpower_sku[offs + i] = pwr; \ 96862306a36Sopenharmony_ci } \ 96962306a36Sopenharmony_ci}) 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic ssize_t 97262306a36Sopenharmony_cimt7915_rate_txpower_get(struct file *file, char __user *user_buf, 97362306a36Sopenharmony_ci size_t count, loff_t *ppos) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct mt7915_phy *phy = file->private_data; 97662306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 97762306a36Sopenharmony_ci s8 txpwr[MT7915_SKU_RATE_NUM]; 97862306a36Sopenharmony_ci static const size_t sz = 2048; 97962306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 98062306a36Sopenharmony_ci int i, offs = 0, len = 0; 98162306a36Sopenharmony_ci ssize_t ret; 98262306a36Sopenharmony_ci char *buf; 98362306a36Sopenharmony_ci u32 reg; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci buf = kzalloc(sz, GFP_KERNEL); 98662306a36Sopenharmony_ci if (!buf) 98762306a36Sopenharmony_ci return -ENOMEM; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci ret = mt7915_mcu_get_txpower_sku(phy, txpwr, sizeof(txpwr)); 99062306a36Sopenharmony_ci if (ret) 99162306a36Sopenharmony_ci goto out; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* Txpower propagation path: TMAC -> TXV -> BBP */ 99462306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, 99562306a36Sopenharmony_ci "\nPhy%d Tx power table (channel %d)\n", 99662306a36Sopenharmony_ci phy != &dev->phy, phy->mt76->chandef.chan->hw_value); 99762306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s\n", 99862306a36Sopenharmony_ci " ", "1m", "2m", "5m", "11m"); 99962306a36Sopenharmony_ci mt7915_txpower_puts(CCK); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, 100262306a36Sopenharmony_ci "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", 100362306a36Sopenharmony_ci " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m", 100462306a36Sopenharmony_ci "54m"); 100562306a36Sopenharmony_ci mt7915_txpower_puts(OFDM); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, 100862306a36Sopenharmony_ci "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", 100962306a36Sopenharmony_ci " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", 101062306a36Sopenharmony_ci "mcs5", "mcs6", "mcs7"); 101162306a36Sopenharmony_ci mt7915_txpower_puts(HT_BW20); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, 101462306a36Sopenharmony_ci "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", 101562306a36Sopenharmony_ci " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", 101662306a36Sopenharmony_ci "mcs6", "mcs7", "mcs32"); 101762306a36Sopenharmony_ci mt7915_txpower_puts(HT_BW40); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, 102062306a36Sopenharmony_ci "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", 102162306a36Sopenharmony_ci " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", 102262306a36Sopenharmony_ci "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11"); 102362306a36Sopenharmony_ci mt7915_txpower_puts(VHT_BW20); 102462306a36Sopenharmony_ci mt7915_txpower_puts(VHT_BW40); 102562306a36Sopenharmony_ci mt7915_txpower_puts(VHT_BW80); 102662306a36Sopenharmony_ci mt7915_txpower_puts(VHT_BW160); 102762306a36Sopenharmony_ci mt7915_txpower_puts(HE_RU26); 102862306a36Sopenharmony_ci mt7915_txpower_puts(HE_RU52); 102962306a36Sopenharmony_ci mt7915_txpower_puts(HE_RU106); 103062306a36Sopenharmony_ci mt7915_txpower_puts(HE_RU242); 103162306a36Sopenharmony_ci mt7915_txpower_puts(HE_RU484); 103262306a36Sopenharmony_ci mt7915_txpower_puts(HE_RU996); 103362306a36Sopenharmony_ci mt7915_txpower_puts(HE_RU2x996); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) : 103662306a36Sopenharmony_ci MT_WF_PHY_TPC_CTRL_STAT_MT7916(band); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci len += scnprintf(buf + len, sz - len, "\nTx power (bbp) : %6ld\n", 103962306a36Sopenharmony_ci mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER)); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ciout: 104462306a36Sopenharmony_ci kfree(buf); 104562306a36Sopenharmony_ci return ret; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic ssize_t 104962306a36Sopenharmony_cimt7915_rate_txpower_set(struct file *file, const char __user *user_buf, 105062306a36Sopenharmony_ci size_t count, loff_t *ppos) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct mt7915_phy *phy = file->private_data; 105362306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 105462306a36Sopenharmony_ci struct mt76_phy *mphy = phy->mt76; 105562306a36Sopenharmony_ci struct mt7915_mcu_txpower_sku req = { 105662306a36Sopenharmony_ci .format_id = TX_POWER_LIMIT_TABLE, 105762306a36Sopenharmony_ci .band_idx = phy->mt76->band_idx, 105862306a36Sopenharmony_ci }; 105962306a36Sopenharmony_ci char buf[100]; 106062306a36Sopenharmony_ci int i, ret, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0; 106162306a36Sopenharmony_ci enum mac80211_rx_encoding mode; 106262306a36Sopenharmony_ci u32 offs = 0, len = 0; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (count >= sizeof(buf)) 106562306a36Sopenharmony_ci return -EINVAL; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (copy_from_user(buf, user_buf, count)) 106862306a36Sopenharmony_ci return -EFAULT; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (count && buf[count - 1] == '\n') 107162306a36Sopenharmony_ci buf[count - 1] = '\0'; 107262306a36Sopenharmony_ci else 107362306a36Sopenharmony_ci buf[count] = '\0'; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (sscanf(buf, "%u %u %u %u %u", 107662306a36Sopenharmony_ci &mode, &pwr160, &pwr80, &pwr40, &pwr20) != 5) { 107762306a36Sopenharmony_ci dev_warn(dev->mt76.dev, 107862306a36Sopenharmony_ci "per bandwidth power limit: Mode BW160 BW80 BW40 BW20"); 107962306a36Sopenharmony_ci return -EINVAL; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (mode > RX_ENC_HE) 108362306a36Sopenharmony_ci return -EINVAL; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (pwr160) 108662306a36Sopenharmony_ci pwr160 = mt7915_get_power_bound(phy, pwr160); 108762306a36Sopenharmony_ci if (pwr80) 108862306a36Sopenharmony_ci pwr80 = mt7915_get_power_bound(phy, pwr80); 108962306a36Sopenharmony_ci if (pwr40) 109062306a36Sopenharmony_ci pwr40 = mt7915_get_power_bound(phy, pwr40); 109162306a36Sopenharmony_ci if (pwr20) 109262306a36Sopenharmony_ci pwr20 = mt7915_get_power_bound(phy, pwr20); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (pwr160 < 0 || pwr80 < 0 || pwr40 < 0 || pwr20 < 0) 109562306a36Sopenharmony_ci return -EINVAL; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 109862306a36Sopenharmony_ci ret = mt7915_mcu_get_txpower_sku(phy, req.txpower_sku, 109962306a36Sopenharmony_ci sizeof(req.txpower_sku)); 110062306a36Sopenharmony_ci if (ret) 110162306a36Sopenharmony_ci goto out; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci mt7915_txpower_sets(SKU_CCK, pwr20, RX_ENC_LEGACY); 110462306a36Sopenharmony_ci mt7915_txpower_sets(SKU_OFDM, pwr20, RX_ENC_LEGACY); 110562306a36Sopenharmony_ci if (mode == RX_ENC_LEGACY) 110662306a36Sopenharmony_ci goto skip; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HT_BW20, pwr20, RX_ENC_HT); 110962306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HT_BW40, pwr40, RX_ENC_HT); 111062306a36Sopenharmony_ci if (mode == RX_ENC_HT) 111162306a36Sopenharmony_ci goto skip; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci mt7915_txpower_sets(SKU_VHT_BW20, pwr20, RX_ENC_VHT); 111462306a36Sopenharmony_ci mt7915_txpower_sets(SKU_VHT_BW40, pwr40, RX_ENC_VHT); 111562306a36Sopenharmony_ci mt7915_txpower_sets(SKU_VHT_BW80, pwr80, RX_ENC_VHT); 111662306a36Sopenharmony_ci mt7915_txpower_sets(SKU_VHT_BW160, pwr160, RX_ENC_VHT); 111762306a36Sopenharmony_ci if (mode == RX_ENC_VHT) 111862306a36Sopenharmony_ci goto skip; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HE_RU26, pwr20, RX_ENC_HE + 1); 112162306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HE_RU52, pwr20, RX_ENC_HE + 1); 112262306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HE_RU106, pwr20, RX_ENC_HE + 1); 112362306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HE_RU242, pwr20, RX_ENC_HE); 112462306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HE_RU484, pwr40, RX_ENC_HE); 112562306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HE_RU996, pwr80, RX_ENC_HE); 112662306a36Sopenharmony_ci mt7915_txpower_sets(SKU_HE_RU2x996, pwr160, RX_ENC_HE); 112762306a36Sopenharmony_ciskip: 112862306a36Sopenharmony_ci ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), 112962306a36Sopenharmony_ci &req, sizeof(req), true); 113062306a36Sopenharmony_ci if (ret) 113162306a36Sopenharmony_ci goto out; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci mphy->txpower_cur = max(mphy->txpower_cur, 113462306a36Sopenharmony_ci max(pwr160, max(pwr80, max(pwr40, pwr20)))); 113562306a36Sopenharmony_ciout: 113662306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci return ret ? ret : count; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic const struct file_operations mt7915_rate_txpower_fops = { 114262306a36Sopenharmony_ci .write = mt7915_rate_txpower_set, 114362306a36Sopenharmony_ci .read = mt7915_rate_txpower_get, 114462306a36Sopenharmony_ci .open = simple_open, 114562306a36Sopenharmony_ci .owner = THIS_MODULE, 114662306a36Sopenharmony_ci .llseek = default_llseek, 114762306a36Sopenharmony_ci}; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic int 115062306a36Sopenharmony_cimt7915_twt_stats(struct seq_file *s, void *data) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci struct mt7915_dev *dev = dev_get_drvdata(s->private); 115362306a36Sopenharmony_ci struct mt7915_twt_flow *iter; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci rcu_read_lock(); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci seq_puts(s, " wcid | id | flags | exp | mantissa"); 115862306a36Sopenharmony_ci seq_puts(s, " | duration | tsf |\n"); 115962306a36Sopenharmony_ci list_for_each_entry_rcu(iter, &dev->twt_list, list) 116062306a36Sopenharmony_ci seq_printf(s, 116162306a36Sopenharmony_ci "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n", 116262306a36Sopenharmony_ci iter->wcid, iter->id, 116362306a36Sopenharmony_ci iter->sched ? 's' : 'u', 116462306a36Sopenharmony_ci iter->protection ? 'p' : '-', 116562306a36Sopenharmony_ci iter->trigger ? 't' : '-', 116662306a36Sopenharmony_ci iter->flowtype ? '-' : 'a', 116762306a36Sopenharmony_ci iter->exp, iter->mantissa, 116862306a36Sopenharmony_ci iter->duration, iter->tsf); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci rcu_read_unlock(); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci return 0; 117362306a36Sopenharmony_ci} 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci/* The index of RF registers use the generic regidx, combined with two parts: 117662306a36Sopenharmony_ci * WF selection [31:24] and offset [23:0]. 117762306a36Sopenharmony_ci */ 117862306a36Sopenharmony_cistatic int 117962306a36Sopenharmony_cimt7915_rf_regval_get(void *data, u64 *val) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct mt7915_dev *dev = data; 118262306a36Sopenharmony_ci u32 regval; 118362306a36Sopenharmony_ci int ret; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci ret = mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, ®val, false); 118662306a36Sopenharmony_ci if (ret) 118762306a36Sopenharmony_ci return ret; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci *val = regval; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci return 0; 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_cistatic int 119562306a36Sopenharmony_cimt7915_rf_regval_set(void *data, u64 val) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct mt7915_dev *dev = data; 119862306a36Sopenharmony_ci u32 val32 = val; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true); 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get, 120462306a36Sopenharmony_ci mt7915_rf_regval_set, "0x%08llx\n"); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ciint mt7915_init_debugfs(struct mt7915_phy *phy) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 120962306a36Sopenharmony_ci bool ext_phy = phy != &dev->phy; 121062306a36Sopenharmony_ci struct dentry *dir; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci dir = mt76_register_debugfs_fops(phy->mt76, NULL); 121362306a36Sopenharmony_ci if (!dir) 121462306a36Sopenharmony_ci return -ENOMEM; 121562306a36Sopenharmony_ci debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug); 121662306a36Sopenharmony_ci debugfs_create_file("muru_stats", 0400, dir, phy, 121762306a36Sopenharmony_ci &mt7915_muru_stats_fops); 121862306a36Sopenharmony_ci debugfs_create_file("hw-queues", 0400, dir, phy, 121962306a36Sopenharmony_ci &mt7915_hw_queues_fops); 122062306a36Sopenharmony_ci debugfs_create_file("xmit-queues", 0400, dir, phy, 122162306a36Sopenharmony_ci &mt7915_xmit_queues_fops); 122262306a36Sopenharmony_ci debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops); 122362306a36Sopenharmony_ci debugfs_create_file("sys_recovery", 0600, dir, phy, 122462306a36Sopenharmony_ci &mt7915_sys_recovery_ops); 122562306a36Sopenharmony_ci debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); 122662306a36Sopenharmony_ci debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); 122762306a36Sopenharmony_ci debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin); 122862306a36Sopenharmony_ci debugfs_create_file("fw_util_wm", 0400, dir, dev, 122962306a36Sopenharmony_ci &mt7915_fw_util_wm_fops); 123062306a36Sopenharmony_ci debugfs_create_file("fw_util_wa", 0400, dir, dev, 123162306a36Sopenharmony_ci &mt7915_fw_util_wa_fops); 123262306a36Sopenharmony_ci debugfs_create_file("implicit_txbf", 0600, dir, dev, 123362306a36Sopenharmony_ci &fops_implicit_txbf); 123462306a36Sopenharmony_ci debugfs_create_file("txpower_sku", 0400, dir, phy, 123562306a36Sopenharmony_ci &mt7915_rate_txpower_fops); 123662306a36Sopenharmony_ci debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, 123762306a36Sopenharmony_ci mt7915_twt_stats); 123862306a36Sopenharmony_ci debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (!dev->dbdc_support || phy->mt76->band_idx) { 124162306a36Sopenharmony_ci debugfs_create_u32("dfs_hw_pattern", 0400, dir, 124262306a36Sopenharmony_ci &dev->hw_pattern); 124362306a36Sopenharmony_ci debugfs_create_file("radar_trigger", 0200, dir, dev, 124462306a36Sopenharmony_ci &fops_radar_trigger); 124562306a36Sopenharmony_ci debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, 124662306a36Sopenharmony_ci mt7915_rdd_monitor); 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (!ext_phy) 125062306a36Sopenharmony_ci dev->debugfs_dir = dir; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci return 0; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic void 125662306a36Sopenharmony_cimt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen, 125762306a36Sopenharmony_ci const void *data, int len) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci static DEFINE_SPINLOCK(lock); 126062306a36Sopenharmony_ci unsigned long flags; 126162306a36Sopenharmony_ci void *dest; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci spin_lock_irqsave(&lock, flags); 126462306a36Sopenharmony_ci dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4); 126562306a36Sopenharmony_ci if (dest) { 126662306a36Sopenharmony_ci *(u32 *)dest = hdrlen + len; 126762306a36Sopenharmony_ci dest += 4; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (hdrlen) { 127062306a36Sopenharmony_ci memcpy(dest, hdr, hdrlen); 127162306a36Sopenharmony_ci dest += hdrlen; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci memcpy(dest, data, len); 127562306a36Sopenharmony_ci relay_flush(dev->relay_fwlog); 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci spin_unlock_irqrestore(&lock, flags); 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_civoid mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct { 128362306a36Sopenharmony_ci __le32 magic; 128462306a36Sopenharmony_ci __le32 timestamp; 128562306a36Sopenharmony_ci __le16 msg_type; 128662306a36Sopenharmony_ci __le16 len; 128762306a36Sopenharmony_ci } hdr = { 128862306a36Sopenharmony_ci .magic = cpu_to_le32(FW_BIN_LOG_MAGIC), 128962306a36Sopenharmony_ci .msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR), 129062306a36Sopenharmony_ci }; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (!dev->relay_fwlog) 129362306a36Sopenharmony_ci return; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0))); 129662306a36Sopenharmony_ci hdr.len = *(__le16 *)data; 129762306a36Sopenharmony_ci mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len); 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cibool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC) 130362306a36Sopenharmony_ci return false; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (dev->relay_fwlog) 130662306a36Sopenharmony_ci mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return true; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS 131262306a36Sopenharmony_ci/** per-station debugfs **/ 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic ssize_t mt7915_sta_fixed_rate_set(struct file *file, 131562306a36Sopenharmony_ci const char __user *user_buf, 131662306a36Sopenharmony_ci size_t count, loff_t *ppos) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 131962306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 132062306a36Sopenharmony_ci struct mt7915_dev *dev = msta->vif->phy->dev; 132162306a36Sopenharmony_ci struct ieee80211_vif *vif; 132262306a36Sopenharmony_ci struct sta_phy phy = {}; 132362306a36Sopenharmony_ci char buf[100]; 132462306a36Sopenharmony_ci int ret; 132562306a36Sopenharmony_ci u32 field; 132662306a36Sopenharmony_ci u8 i, gi, he_ltf; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (count >= sizeof(buf)) 132962306a36Sopenharmony_ci return -EINVAL; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (copy_from_user(buf, user_buf, count)) 133262306a36Sopenharmony_ci return -EFAULT; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (count && buf[count - 1] == '\n') 133562306a36Sopenharmony_ci buf[count - 1] = '\0'; 133662306a36Sopenharmony_ci else 133762306a36Sopenharmony_ci buf[count] = '\0'; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci /* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9 134062306a36Sopenharmony_ci * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3 134162306a36Sopenharmony_ci * nss - vht: 1~4, he: 1~4, others: ignore 134262306a36Sopenharmony_ci * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2 134362306a36Sopenharmony_ci * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2 134462306a36Sopenharmony_ci * ldpc - off: 0, on: 1 134562306a36Sopenharmony_ci * stbc - off: 0, on: 1 134662306a36Sopenharmony_ci * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 134762306a36Sopenharmony_ci */ 134862306a36Sopenharmony_ci if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu", 134962306a36Sopenharmony_ci &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi, 135062306a36Sopenharmony_ci &phy.ldpc, &phy.stbc, &he_ltf) != 8) { 135162306a36Sopenharmony_ci dev_warn(dev->mt76.dev, 135262306a36Sopenharmony_ci "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n"); 135362306a36Sopenharmony_ci field = RATE_PARAM_AUTO; 135462306a36Sopenharmony_ci goto out; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0); 135862306a36Sopenharmony_ci for (i = 0; i <= phy.bw; i++) { 135962306a36Sopenharmony_ci phy.sgi |= gi << (i << sta->deflink.he_cap.has_he); 136062306a36Sopenharmony_ci phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci field = RATE_PARAM_FIXED; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ciout: 136562306a36Sopenharmony_ci vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); 136662306a36Sopenharmony_ci ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field); 136762306a36Sopenharmony_ci if (ret) 136862306a36Sopenharmony_ci return -EFAULT; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci return count; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cistatic const struct file_operations fops_fixed_rate = { 137462306a36Sopenharmony_ci .write = mt7915_sta_fixed_rate_set, 137562306a36Sopenharmony_ci .open = simple_open, 137662306a36Sopenharmony_ci .owner = THIS_MODULE, 137762306a36Sopenharmony_ci .llseek = default_llseek, 137862306a36Sopenharmony_ci}; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_cistatic int 138162306a36Sopenharmony_cimt7915_queues_show(struct seq_file *s, void *data) 138262306a36Sopenharmony_ci{ 138362306a36Sopenharmony_ci struct ieee80211_sta *sta = s->private; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci mt7915_sta_hw_queue_read(s, sta); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci return 0; 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_queues); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_civoid mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 139362306a36Sopenharmony_ci struct ieee80211_sta *sta, struct dentry *dir) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); 139662306a36Sopenharmony_ci debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops); 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci#endif 1400