Path: blob/main/sys/contrib/dev/athk/ath12k/debugfs.c
178699 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.3* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.4*/56#include "core.h"7#include "dp_tx.h"8#include "debug.h"9#include "debugfs.h"10#include "debugfs_htt_stats.h"1112static ssize_t ath12k_write_simulate_radar(struct file *file,13const char __user *user_buf,14size_t count, loff_t *ppos)15{16struct ath12k *ar = file->private_data;17int ret;1819wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);20ret = ath12k_wmi_simulate_radar(ar);21if (ret)22goto exit;2324ret = count;25exit:26wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);27return ret;28}2930static const struct file_operations fops_simulate_radar = {31.write = ath12k_write_simulate_radar,32.open = simple_open33};3435static ssize_t ath12k_read_simulate_fw_crash(struct file *file,36char __user *user_buf,37size_t count, loff_t *ppos)38{39const char buf[] =40"To simulate firmware crash write one of the keywords to this file:\n"41"`assert` - send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n";4243return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));44}4546static ssize_t47ath12k_write_simulate_fw_crash(struct file *file,48const char __user *user_buf,49size_t count, loff_t *ppos)50{51struct ath12k_base *ab = file->private_data;52struct ath12k_pdev *pdev;53struct ath12k *ar = NULL;54char buf[32] = {};55int i, ret;56ssize_t rc;5758/* filter partial writes and invalid commands */59if (*ppos != 0 || count >= sizeof(buf) || count == 0)60return -EINVAL;6162rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);63if (rc < 0)64return rc;6566/* drop the possible '\n' from the end */67if (buf[*ppos - 1] == '\n')68buf[*ppos - 1] = '\0';6970for (i = 0; i < ab->num_radios; i++) {71pdev = &ab->pdevs[i];72ar = pdev->ar;73if (ar)74break;75}7677if (!ar)78return -ENETDOWN;7980if (!strcmp(buf, "assert")) {81ath12k_info(ab, "simulating firmware assert crash\n");82ret = ath12k_wmi_force_fw_hang_cmd(ar,83ATH12K_WMI_FW_HANG_ASSERT_TYPE,84ATH12K_WMI_FW_HANG_DELAY);85} else {86return -EINVAL;87}8889if (ret) {90ath12k_warn(ab, "failed to simulate firmware crash: %d\n", ret);91return ret;92}9394return count;95}9697static const struct file_operations fops_simulate_fw_crash = {98.read = ath12k_read_simulate_fw_crash,99.write = ath12k_write_simulate_fw_crash,100.open = simple_open,101.owner = THIS_MODULE,102.llseek = default_llseek,103};104105static ssize_t ath12k_write_tpc_stats_type(struct file *file,106const char __user *user_buf,107size_t count, loff_t *ppos)108{109struct ath12k *ar = file->private_data;110u8 type;111int ret;112113ret = kstrtou8_from_user(user_buf, count, 0, &type);114if (ret)115return ret;116117if (type >= WMI_HALPHY_PDEV_TX_STATS_MAX)118return -EINVAL;119120spin_lock_bh(&ar->data_lock);121ar->debug.tpc_stats_type = type;122spin_unlock_bh(&ar->data_lock);123124return count;125}126127static int ath12k_debug_tpc_stats_request(struct ath12k *ar)128{129enum wmi_halphy_ctrl_path_stats_id tpc_stats_sub_id;130struct ath12k_base *ab = ar->ab;131int ret;132133lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);134135reinit_completion(&ar->debug.tpc_complete);136137spin_lock_bh(&ar->data_lock);138ar->debug.tpc_request = true;139tpc_stats_sub_id = ar->debug.tpc_stats_type;140spin_unlock_bh(&ar->data_lock);141142ret = ath12k_wmi_send_tpc_stats_request(ar, tpc_stats_sub_id);143if (ret) {144ath12k_warn(ab, "failed to request pdev tpc stats: %d\n", ret);145spin_lock_bh(&ar->data_lock);146ar->debug.tpc_request = false;147spin_unlock_bh(&ar->data_lock);148return ret;149}150151return 0;152}153154static int ath12k_get_tpc_ctl_mode_idx(struct wmi_tpc_stats_arg *tpc_stats,155enum wmi_tpc_pream_bw pream_bw, int *mode_idx)156{157u32 chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);158u8 band;159160band = ((chan_freq > ATH12K_MIN_6GHZ_FREQ) ? NL80211_BAND_6GHZ :161((chan_freq > ATH12K_MIN_5GHZ_FREQ) ? NL80211_BAND_5GHZ :162NL80211_BAND_2GHZ));163164if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {165switch (pream_bw) {166case WMI_TPC_PREAM_HT20:167case WMI_TPC_PREAM_VHT20:168*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT20_5GHZ_6GHZ;169break;170case WMI_TPC_PREAM_HE20:171case WMI_TPC_PREAM_EHT20:172*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT20_5GHZ_6GHZ;173break;174case WMI_TPC_PREAM_HT40:175case WMI_TPC_PREAM_VHT40:176*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT40_5GHZ_6GHZ;177break;178case WMI_TPC_PREAM_HE40:179case WMI_TPC_PREAM_EHT40:180*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT40_5GHZ_6GHZ;181break;182case WMI_TPC_PREAM_VHT80:183*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT80_5GHZ_6GHZ;184break;185case WMI_TPC_PREAM_EHT60:186*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT80_SU_PUNC20;187break;188case WMI_TPC_PREAM_HE80:189case WMI_TPC_PREAM_EHT80:190*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT80_5GHZ_6GHZ;191break;192case WMI_TPC_PREAM_VHT160:193*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT160_5GHZ_6GHZ;194break;195case WMI_TPC_PREAM_EHT120:196case WMI_TPC_PREAM_EHT140:197*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT160_SU_PUNC20;198break;199case WMI_TPC_PREAM_HE160:200case WMI_TPC_PREAM_EHT160:201*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT160_5GHZ_6GHZ;202break;203case WMI_TPC_PREAM_EHT200:204*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC120;205break;206case WMI_TPC_PREAM_EHT240:207*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC80;208break;209case WMI_TPC_PREAM_EHT280:210*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC40;211break;212case WMI_TPC_PREAM_EHT320:213*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT320_5GHZ_6GHZ;214break;215default:216/* for 5GHZ and 6GHZ, default case will be for OFDM */217*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_5GHZ_6GHZ;218break;219}220} else {221switch (pream_bw) {222case WMI_TPC_PREAM_OFDM:223*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_2GHZ;224break;225case WMI_TPC_PREAM_HT20:226case WMI_TPC_PREAM_VHT20:227case WMI_TPC_PREAM_HE20:228case WMI_TPC_PREAM_EHT20:229*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT20_2GHZ;230break;231case WMI_TPC_PREAM_HT40:232case WMI_TPC_PREAM_VHT40:233case WMI_TPC_PREAM_HE40:234case WMI_TPC_PREAM_EHT40:235*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT40_2GHZ;236break;237default:238/* for 2GHZ, default case will be CCK */239*mode_idx = ATH12K_TPC_STATS_CTL_MODE_CCK_2GHZ;240break;241}242}243244return 0;245}246247static s16 ath12k_tpc_get_rate(struct ath12k *ar,248struct wmi_tpc_stats_arg *tpc_stats,249u32 rate_idx, u32 num_chains, u32 rate_code,250enum wmi_tpc_pream_bw pream_bw,251enum wmi_halphy_ctrl_path_stats_id type,252u32 eht_rate_idx)253{254u32 tot_nss, tot_modes, txbf_on_off, index_offset1, index_offset2, index_offset3;255u8 chain_idx, stm_idx, num_streams;256bool is_mu, txbf_enabled = 0;257s8 rates_ctl_min, tpc_ctl;258s16 rates, tpc, reg_pwr;259u16 rate1, rate2;260int mode, ret;261262num_streams = 1 + ATH12K_HW_NSS(rate_code);263chain_idx = num_chains - 1;264stm_idx = num_streams - 1;265mode = -1;266267ret = ath12k_get_tpc_ctl_mode_idx(tpc_stats, pream_bw, &mode);268if (ret) {269ath12k_warn(ar->ab, "Invalid mode index received\n");270tpc = TPC_INVAL;271goto out;272}273274if (num_chains < num_streams) {275tpc = TPC_INVAL;276goto out;277}278279if (le32_to_cpu(tpc_stats->tpc_config.num_tx_chain) <= 1) {280tpc = TPC_INVAL;281goto out;282}283284if (type == WMI_HALPHY_PDEV_TX_SUTXBF_STATS ||285type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS)286txbf_enabled = 1;287288if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||289type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {290is_mu = true;291} else {292is_mu = false;293}294295/* Below is the min calculation of ctl array, rates array and296* regulator power table. tpc is minimum of all 3297*/298if (pream_bw >= WMI_TPC_PREAM_EHT20 && pream_bw <= WMI_TPC_PREAM_EHT320) {299rate2 = tpc_stats->rates_array2.rate_array[eht_rate_idx];300if (is_mu)301rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_MU);302else303rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_SU);304} else {305rate1 = tpc_stats->rates_array1.rate_array[rate_idx];306if (is_mu)307rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_MU);308else309rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_SU);310}311312if (tpc_stats->tlvs_rcvd & WMI_TPC_CTL_PWR_ARRAY) {313tot_nss = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d1);314tot_modes = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d2);315txbf_on_off = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d3);316index_offset1 = txbf_on_off * tot_modes * tot_nss;317index_offset2 = tot_modes * tot_nss;318index_offset3 = tot_nss;319320tpc_ctl = *(tpc_stats->ctl_array.ctl_pwr_table +321chain_idx * index_offset1 + txbf_enabled * index_offset2322+ mode * index_offset3 + stm_idx);323} else {324tpc_ctl = TPC_MAX;325ath12k_warn(ar->ab,326"ctl array for tpc stats not received from fw\n");327}328329rates_ctl_min = min_t(s16, rates, tpc_ctl);330331reg_pwr = tpc_stats->max_reg_allowed_power.reg_pwr_array[chain_idx];332333if (reg_pwr < 0)334reg_pwr = TPC_INVAL;335336tpc = min_t(s16, rates_ctl_min, reg_pwr);337338/* MODULATION_LIMIT is the maximum power limit,tpc should not exceed339* modulation limit even if min tpc of all three array is greater340* modulation limit341*/342tpc = min_t(s16, tpc, MODULATION_LIMIT);343344out:345return tpc;346}347348static u16 ath12k_get_ratecode(u16 pream_idx, u16 nss, u16 mcs_rate)349{350u16 mode_type = ~0;351352/* Below assignments are just for printing purpose only */353switch (pream_idx) {354case WMI_TPC_PREAM_CCK:355mode_type = WMI_RATE_PREAMBLE_CCK;356break;357case WMI_TPC_PREAM_OFDM:358mode_type = WMI_RATE_PREAMBLE_OFDM;359break;360case WMI_TPC_PREAM_HT20:361case WMI_TPC_PREAM_HT40:362mode_type = WMI_RATE_PREAMBLE_HT;363break;364case WMI_TPC_PREAM_VHT20:365case WMI_TPC_PREAM_VHT40:366case WMI_TPC_PREAM_VHT80:367case WMI_TPC_PREAM_VHT160:368mode_type = WMI_RATE_PREAMBLE_VHT;369break;370case WMI_TPC_PREAM_HE20:371case WMI_TPC_PREAM_HE40:372case WMI_TPC_PREAM_HE80:373case WMI_TPC_PREAM_HE160:374mode_type = WMI_RATE_PREAMBLE_HE;375break;376case WMI_TPC_PREAM_EHT20:377case WMI_TPC_PREAM_EHT40:378case WMI_TPC_PREAM_EHT60:379case WMI_TPC_PREAM_EHT80:380case WMI_TPC_PREAM_EHT120:381case WMI_TPC_PREAM_EHT140:382case WMI_TPC_PREAM_EHT160:383case WMI_TPC_PREAM_EHT200:384case WMI_TPC_PREAM_EHT240:385case WMI_TPC_PREAM_EHT280:386case WMI_TPC_PREAM_EHT320:387mode_type = WMI_RATE_PREAMBLE_EHT;388if (mcs_rate == 0 || mcs_rate == 1)389mcs_rate += 14;390else391mcs_rate -= 2;392break;393default:394return mode_type;395}396return ((mode_type << 8) | ((nss & 0x7) << 5) | (mcs_rate & 0x1F));397}398399static bool ath12k_he_supports_extra_mcs(struct ath12k *ar, int freq)400{401struct ath12k_pdev_cap *cap = &ar->pdev->cap;402struct ath12k_band_cap *cap_band;403bool extra_mcs_supported;404405if (freq <= ATH12K_2GHZ_MAX_FREQUENCY)406cap_band = &cap->band[NL80211_BAND_2GHZ];407else if (freq <= ATH12K_5GHZ_MAX_FREQUENCY)408cap_band = &cap->band[NL80211_BAND_5GHZ];409else410cap_band = &cap->band[NL80211_BAND_6GHZ];411412extra_mcs_supported = u32_get_bits(cap_band->he_cap_info[1],413HE_EXTRA_MCS_SUPPORT);414return extra_mcs_supported;415}416417static int ath12k_tpc_fill_pream(struct ath12k *ar, char *buf, int buf_len, int len,418enum wmi_tpc_pream_bw pream_bw, u32 max_rix,419int max_nss, int max_rates, int pream_type,420enum wmi_halphy_ctrl_path_stats_id tpc_type,421int rate_idx, int eht_rate_idx)422{423struct wmi_tpc_stats_arg *tpc_stats = ar->debug.tpc_stats;424int nss, rates, chains;425u8 active_tx_chains;426u16 rate_code;427s16 tpc;428429static const char *const pream_str[] = {430[WMI_TPC_PREAM_CCK] = "CCK",431[WMI_TPC_PREAM_OFDM] = "OFDM",432[WMI_TPC_PREAM_HT20] = "HT20",433[WMI_TPC_PREAM_HT40] = "HT40",434[WMI_TPC_PREAM_VHT20] = "VHT20",435[WMI_TPC_PREAM_VHT40] = "VHT40",436[WMI_TPC_PREAM_VHT80] = "VHT80",437[WMI_TPC_PREAM_VHT160] = "VHT160",438[WMI_TPC_PREAM_HE20] = "HE20",439[WMI_TPC_PREAM_HE40] = "HE40",440[WMI_TPC_PREAM_HE80] = "HE80",441[WMI_TPC_PREAM_HE160] = "HE160",442[WMI_TPC_PREAM_EHT20] = "EHT20",443[WMI_TPC_PREAM_EHT40] = "EHT40",444[WMI_TPC_PREAM_EHT60] = "EHT60",445[WMI_TPC_PREAM_EHT80] = "EHT80",446[WMI_TPC_PREAM_EHT120] = "EHT120",447[WMI_TPC_PREAM_EHT140] = "EHT140",448[WMI_TPC_PREAM_EHT160] = "EHT160",449[WMI_TPC_PREAM_EHT200] = "EHT200",450[WMI_TPC_PREAM_EHT240] = "EHT240",451[WMI_TPC_PREAM_EHT280] = "EHT280",452[WMI_TPC_PREAM_EHT320] = "EHT320"};453454active_tx_chains = ar->num_tx_chains;455456for (nss = 0; nss < max_nss; nss++) {457for (rates = 0; rates < max_rates; rates++, rate_idx++, max_rix++) {458/* FW send extra MCS(10&11) for VHT and HE rates,459* this is not used. Hence skipping it here460*/461if (pream_type == WMI_RATE_PREAMBLE_VHT &&462rates > ATH12K_VHT_MCS_MAX)463continue;464465if (pream_type == WMI_RATE_PREAMBLE_HE &&466rates > ATH12K_HE_MCS_MAX)467continue;468469if (pream_type == WMI_RATE_PREAMBLE_EHT &&470rates > ATH12K_EHT_MCS_MAX)471continue;472473rate_code = ath12k_get_ratecode(pream_bw, nss, rates);474len += scnprintf(buf + len, buf_len - len,475"%d\t %s\t 0x%03x\t", max_rix,476pream_str[pream_bw], rate_code);477478for (chains = 0; chains < active_tx_chains; chains++) {479if (nss > chains) {480len += scnprintf(buf + len,481buf_len - len,482"\t%s", "NA");483} else {484tpc = ath12k_tpc_get_rate(ar, tpc_stats,485rate_idx, chains + 1,486rate_code, pream_bw,487tpc_type,488eht_rate_idx);489490if (tpc == TPC_INVAL) {491len += scnprintf(buf + len,492buf_len - len, "\tNA");493} else {494len += scnprintf(buf + len,495buf_len - len, "\t%d",496tpc);497}498}499}500len += scnprintf(buf + len, buf_len - len, "\n");501502if (pream_type == WMI_RATE_PREAMBLE_EHT)503/*For fetching the next eht rates pwr from rates array2*/504++eht_rate_idx;505}506}507508return len;509}510511static int ath12k_tpc_stats_print(struct ath12k *ar,512struct wmi_tpc_stats_arg *tpc_stats,513char *buf, size_t len,514enum wmi_halphy_ctrl_path_stats_id type)515{516u32 eht_idx = 0, pream_idx = 0, rate_pream_idx = 0, total_rates = 0, max_rix = 0;517u32 chan_freq, num_tx_chain, caps, i, j = 1;518size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;519u8 nss, active_tx_chains;520bool he_ext_mcs;521static const char *const type_str[WMI_HALPHY_PDEV_TX_STATS_MAX] = {522[WMI_HALPHY_PDEV_TX_SU_STATS] = "SU",523[WMI_HALPHY_PDEV_TX_SUTXBF_STATS] = "SU WITH TXBF",524[WMI_HALPHY_PDEV_TX_MU_STATS] = "MU",525[WMI_HALPHY_PDEV_TX_MUTXBF_STATS] = "MU WITH TXBF"};526527u8 max_rates[WMI_TPC_PREAM_MAX] = {528[WMI_TPC_PREAM_CCK] = ATH12K_CCK_RATES,529[WMI_TPC_PREAM_OFDM] = ATH12K_OFDM_RATES,530[WMI_TPC_PREAM_HT20] = ATH12K_HT_RATES,531[WMI_TPC_PREAM_HT40] = ATH12K_HT_RATES,532[WMI_TPC_PREAM_VHT20] = ATH12K_VHT_RATES,533[WMI_TPC_PREAM_VHT40] = ATH12K_VHT_RATES,534[WMI_TPC_PREAM_VHT80] = ATH12K_VHT_RATES,535[WMI_TPC_PREAM_VHT160] = ATH12K_VHT_RATES,536[WMI_TPC_PREAM_HE20] = ATH12K_HE_RATES,537[WMI_TPC_PREAM_HE40] = ATH12K_HE_RATES,538[WMI_TPC_PREAM_HE80] = ATH12K_HE_RATES,539[WMI_TPC_PREAM_HE160] = ATH12K_HE_RATES,540[WMI_TPC_PREAM_EHT20] = ATH12K_EHT_RATES,541[WMI_TPC_PREAM_EHT40] = ATH12K_EHT_RATES,542[WMI_TPC_PREAM_EHT60] = ATH12K_EHT_RATES,543[WMI_TPC_PREAM_EHT80] = ATH12K_EHT_RATES,544[WMI_TPC_PREAM_EHT120] = ATH12K_EHT_RATES,545[WMI_TPC_PREAM_EHT140] = ATH12K_EHT_RATES,546[WMI_TPC_PREAM_EHT160] = ATH12K_EHT_RATES,547[WMI_TPC_PREAM_EHT200] = ATH12K_EHT_RATES,548[WMI_TPC_PREAM_EHT240] = ATH12K_EHT_RATES,549[WMI_TPC_PREAM_EHT280] = ATH12K_EHT_RATES,550[WMI_TPC_PREAM_EHT320] = ATH12K_EHT_RATES};551static const u8 max_nss[WMI_TPC_PREAM_MAX] = {552[WMI_TPC_PREAM_CCK] = ATH12K_NSS_1,553[WMI_TPC_PREAM_OFDM] = ATH12K_NSS_1,554[WMI_TPC_PREAM_HT20] = ATH12K_NSS_4,555[WMI_TPC_PREAM_HT40] = ATH12K_NSS_4,556[WMI_TPC_PREAM_VHT20] = ATH12K_NSS_8,557[WMI_TPC_PREAM_VHT40] = ATH12K_NSS_8,558[WMI_TPC_PREAM_VHT80] = ATH12K_NSS_8,559[WMI_TPC_PREAM_VHT160] = ATH12K_NSS_4,560[WMI_TPC_PREAM_HE20] = ATH12K_NSS_8,561[WMI_TPC_PREAM_HE40] = ATH12K_NSS_8,562[WMI_TPC_PREAM_HE80] = ATH12K_NSS_8,563[WMI_TPC_PREAM_HE160] = ATH12K_NSS_4,564[WMI_TPC_PREAM_EHT20] = ATH12K_NSS_4,565[WMI_TPC_PREAM_EHT40] = ATH12K_NSS_4,566[WMI_TPC_PREAM_EHT60] = ATH12K_NSS_4,567[WMI_TPC_PREAM_EHT80] = ATH12K_NSS_4,568[WMI_TPC_PREAM_EHT120] = ATH12K_NSS_4,569[WMI_TPC_PREAM_EHT140] = ATH12K_NSS_4,570[WMI_TPC_PREAM_EHT160] = ATH12K_NSS_4,571[WMI_TPC_PREAM_EHT200] = ATH12K_NSS_4,572[WMI_TPC_PREAM_EHT240] = ATH12K_NSS_4,573[WMI_TPC_PREAM_EHT280] = ATH12K_NSS_4,574[WMI_TPC_PREAM_EHT320] = ATH12K_NSS_4};575576u16 rate_idx[WMI_TPC_PREAM_MAX] = {}, eht_rate_idx[WMI_TPC_PREAM_MAX] = {};577static const u8 pream_type[WMI_TPC_PREAM_MAX] = {578[WMI_TPC_PREAM_CCK] = WMI_RATE_PREAMBLE_CCK,579[WMI_TPC_PREAM_OFDM] = WMI_RATE_PREAMBLE_OFDM,580[WMI_TPC_PREAM_HT20] = WMI_RATE_PREAMBLE_HT,581[WMI_TPC_PREAM_HT40] = WMI_RATE_PREAMBLE_HT,582[WMI_TPC_PREAM_VHT20] = WMI_RATE_PREAMBLE_VHT,583[WMI_TPC_PREAM_VHT40] = WMI_RATE_PREAMBLE_VHT,584[WMI_TPC_PREAM_VHT80] = WMI_RATE_PREAMBLE_VHT,585[WMI_TPC_PREAM_VHT160] = WMI_RATE_PREAMBLE_VHT,586[WMI_TPC_PREAM_HE20] = WMI_RATE_PREAMBLE_HE,587[WMI_TPC_PREAM_HE40] = WMI_RATE_PREAMBLE_HE,588[WMI_TPC_PREAM_HE80] = WMI_RATE_PREAMBLE_HE,589[WMI_TPC_PREAM_HE160] = WMI_RATE_PREAMBLE_HE,590[WMI_TPC_PREAM_EHT20] = WMI_RATE_PREAMBLE_EHT,591[WMI_TPC_PREAM_EHT40] = WMI_RATE_PREAMBLE_EHT,592[WMI_TPC_PREAM_EHT60] = WMI_RATE_PREAMBLE_EHT,593[WMI_TPC_PREAM_EHT80] = WMI_RATE_PREAMBLE_EHT,594[WMI_TPC_PREAM_EHT120] = WMI_RATE_PREAMBLE_EHT,595[WMI_TPC_PREAM_EHT140] = WMI_RATE_PREAMBLE_EHT,596[WMI_TPC_PREAM_EHT160] = WMI_RATE_PREAMBLE_EHT,597[WMI_TPC_PREAM_EHT200] = WMI_RATE_PREAMBLE_EHT,598[WMI_TPC_PREAM_EHT240] = WMI_RATE_PREAMBLE_EHT,599[WMI_TPC_PREAM_EHT280] = WMI_RATE_PREAMBLE_EHT,600[WMI_TPC_PREAM_EHT320] = WMI_RATE_PREAMBLE_EHT};601602chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);603num_tx_chain = le32_to_cpu(tpc_stats->tpc_config.num_tx_chain);604caps = le32_to_cpu(tpc_stats->tpc_config.caps);605606active_tx_chains = ar->num_tx_chains;607he_ext_mcs = ath12k_he_supports_extra_mcs(ar, chan_freq);608609/* mcs 12&13 is sent by FW for certain HWs in rate array, skipping it as610* it is not supported611*/612if (he_ext_mcs) {613for (i = WMI_TPC_PREAM_HE20; i <= WMI_TPC_PREAM_HE160; ++i)614max_rates[i] = ATH12K_HE_RATES;615}616617if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||618type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {619pream_idx = WMI_TPC_PREAM_VHT20;620621for (i = WMI_TPC_PREAM_CCK; i <= WMI_TPC_PREAM_HT40; ++i)622max_rix += max_nss[i] * max_rates[i];623}624/* Enumerate all the rate indices */625for (i = rate_pream_idx + 1; i < WMI_TPC_PREAM_MAX; i++) {626nss = (max_nss[i - 1] < num_tx_chain ?627max_nss[i - 1] : num_tx_chain);628629rate_idx[i] = rate_idx[i - 1] + max_rates[i - 1] * nss;630631if (pream_type[i] == WMI_RATE_PREAMBLE_EHT) {632eht_rate_idx[j] = eht_rate_idx[j - 1] + max_rates[i] * nss;633++j;634}635}636637for (i = 0; i < WMI_TPC_PREAM_MAX; i++) {638nss = (max_nss[i] < num_tx_chain ?639max_nss[i] : num_tx_chain);640total_rates += max_rates[i] * nss;641}642643len += scnprintf(buf + len, buf_len - len,644"No.of rates-%d\n", total_rates);645646len += scnprintf(buf + len, buf_len - len,647"**************** %s ****************\n",648type_str[type]);649len += scnprintf(buf + len, buf_len - len,650"\t\t\t\tTPC values for Active chains\n");651len += scnprintf(buf + len, buf_len - len,652"Rate idx Preamble Rate code");653654for (i = 1; i <= active_tx_chains; ++i) {655len += scnprintf(buf + len, buf_len - len,656"\t%d-Chain", i);657}658659len += scnprintf(buf + len, buf_len - len, "\n");660for (i = pream_idx; i < WMI_TPC_PREAM_MAX; i++) {661if (chan_freq <= 2483) {662if (i == WMI_TPC_PREAM_VHT80 ||663i == WMI_TPC_PREAM_VHT160 ||664i == WMI_TPC_PREAM_HE80 ||665i == WMI_TPC_PREAM_HE160 ||666(i >= WMI_TPC_PREAM_EHT60 &&667i <= WMI_TPC_PREAM_EHT320)) {668max_rix += max_nss[i] * max_rates[i];669continue;670}671} else {672if (i == WMI_TPC_PREAM_CCK) {673max_rix += max_rates[i];674continue;675}676}677678nss = (max_nss[i] < ar->num_tx_chains ? max_nss[i] : ar->num_tx_chains);679680if (!(caps &681(1 << ATH12K_TPC_STATS_SUPPORT_BE_PUNC))) {682if (i == WMI_TPC_PREAM_EHT60 || i == WMI_TPC_PREAM_EHT120 ||683i == WMI_TPC_PREAM_EHT140 || i == WMI_TPC_PREAM_EHT200 ||684i == WMI_TPC_PREAM_EHT240 || i == WMI_TPC_PREAM_EHT280) {685max_rix += max_nss[i] * max_rates[i];686continue;687}688}689690len = ath12k_tpc_fill_pream(ar, buf, buf_len, len, i, max_rix, nss,691max_rates[i], pream_type[i],692type, rate_idx[i], eht_rate_idx[eht_idx]);693694if (pream_type[i] == WMI_RATE_PREAMBLE_EHT)695/*For fetch the next index eht rates from rates array2*/696++eht_idx;697698max_rix += max_nss[i] * max_rates[i];699}700return len;701}702703static void ath12k_tpc_stats_fill(struct ath12k *ar,704struct wmi_tpc_stats_arg *tpc_stats,705char *buf)706{707size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;708struct wmi_tpc_config_params *tpc;709size_t len = 0;710711if (!tpc_stats) {712ath12k_warn(ar->ab, "failed to find tpc stats\n");713return;714}715716spin_lock_bh(&ar->data_lock);717718tpc = &tpc_stats->tpc_config;719len += scnprintf(buf + len, buf_len - len, "\n");720len += scnprintf(buf + len, buf_len - len,721"*************** TPC config **************\n");722len += scnprintf(buf + len, buf_len - len,723"* powers are in 0.25 dBm steps\n");724len += scnprintf(buf + len, buf_len - len,725"reg domain-%d\t\tchan freq-%d\n",726tpc->reg_domain, tpc->chan_freq);727len += scnprintf(buf + len, buf_len - len,728"power limit-%d\t\tmax reg-domain Power-%d\n",729le32_to_cpu(tpc->twice_max_reg_power) / 2, tpc->power_limit);730len += scnprintf(buf + len, buf_len - len,731"No.of tx chain-%d\t",732ar->num_tx_chains);733734ath12k_tpc_stats_print(ar, tpc_stats, buf, len,735ar->debug.tpc_stats_type);736737spin_unlock_bh(&ar->data_lock);738}739740static int ath12k_open_tpc_stats(struct inode *inode, struct file *file)741{742struct ath12k *ar = inode->i_private;743struct ath12k_hw *ah = ath12k_ar_to_ah(ar);744int ret;745746guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);747748if (ah->state != ATH12K_HW_STATE_ON) {749ath12k_warn(ar->ab, "Interface not up\n");750return -ENETDOWN;751}752753void *buf __free(kfree) = kzalloc(ATH12K_TPC_STATS_BUF_SIZE, GFP_KERNEL);754if (!buf)755return -ENOMEM;756757ret = ath12k_debug_tpc_stats_request(ar);758if (ret) {759ath12k_warn(ar->ab, "failed to request tpc stats: %d\n",760ret);761return ret;762}763764if (!wait_for_completion_timeout(&ar->debug.tpc_complete, TPC_STATS_WAIT_TIME)) {765spin_lock_bh(&ar->data_lock);766ath12k_wmi_free_tpc_stats_mem(ar);767ar->debug.tpc_request = false;768spin_unlock_bh(&ar->data_lock);769return -ETIMEDOUT;770}771772ath12k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);773file->private_data = no_free_ptr(buf);774775spin_lock_bh(&ar->data_lock);776ath12k_wmi_free_tpc_stats_mem(ar);777spin_unlock_bh(&ar->data_lock);778779return 0;780}781782static ssize_t ath12k_read_tpc_stats(struct file *file,783char __user *user_buf,784size_t count, loff_t *ppos)785{786const char *buf = file->private_data;787size_t len = strlen(buf);788789return simple_read_from_buffer(user_buf, count, ppos, buf, len);790}791792static int ath12k_release_tpc_stats(struct inode *inode,793struct file *file)794{795kfree(file->private_data);796return 0;797}798799static const struct file_operations fops_tpc_stats = {800.open = ath12k_open_tpc_stats,801.release = ath12k_release_tpc_stats,802.read = ath12k_read_tpc_stats,803.owner = THIS_MODULE,804.llseek = default_llseek,805};806807static const struct file_operations fops_tpc_stats_type = {808.write = ath12k_write_tpc_stats_type,809.open = simple_open,810.llseek = default_llseek,811};812813static ssize_t ath12k_write_extd_rx_stats(struct file *file,814const char __user *ubuf,815size_t count, loff_t *ppos)816{817struct ath12k *ar = file->private_data;818struct htt_rx_ring_tlv_filter tlv_filter = {};819u32 ring_id, rx_filter = 0;820bool enable;821int ret, i;822823if (kstrtobool_from_user(ubuf, count, &enable))824return -EINVAL;825826wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);827828if (!ar->ab->hw_params->rxdma1_enable) {829ret = count;830goto exit;831}832833if (ar->ah->state != ATH12K_HW_STATE_ON) {834ret = -ENETDOWN;835goto exit;836}837838if (enable == ar->debug.extd_rx_stats) {839ret = count;840goto exit;841}842843if (enable) {844rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START;845rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;846rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;847rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;848rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;849rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;850rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START_USER_INFO;851852tlv_filter.rx_filter = rx_filter;853tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;854tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;855tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;856tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |857HTT_RX_FP_DATA_FILTER_FLASG3;858} else {859tlv_filter = ath12k_mac_mon_status_filter_default;860}861862ar->debug.rx_filter = tlv_filter.rx_filter;863864for (i = 0; i < ar->ab->hw_params->num_rxdma_per_pdev; i++) {865ring_id = ar->dp.rxdma_mon_dst_ring[i].ring_id;866ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id + i,867HAL_RXDMA_MONITOR_DST,868DP_RXDMA_REFILL_RING_SIZE,869&tlv_filter);870if (ret) {871ath12k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");872goto exit;873}874}875876ar->debug.extd_rx_stats = !!enable;877ret = count;878exit:879wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);880return ret;881}882883static ssize_t ath12k_read_extd_rx_stats(struct file *file,884char __user *ubuf,885size_t count, loff_t *ppos)886{887struct ath12k *ar = file->private_data;888char buf[32];889int len = 0;890891wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);892len = scnprintf(buf, sizeof(buf) - len, "%d\n",893ar->debug.extd_rx_stats);894wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);895896return simple_read_from_buffer(ubuf, count, ppos, buf, len);897}898899static const struct file_operations fops_extd_rx_stats = {900.read = ath12k_read_extd_rx_stats,901.write = ath12k_write_extd_rx_stats,902.open = simple_open,903};904905static int ath12k_open_link_stats(struct inode *inode, struct file *file)906{907struct ath12k_vif *ahvif = inode->i_private;908size_t len = 0, buf_len = (PAGE_SIZE * 2);909struct ath12k_link_stats linkstat;910struct ath12k_link_vif *arvif;911unsigned long links_map;912struct wiphy *wiphy;913int link_id, i;914char *buf;915916if (!ahvif)917return -EINVAL;918919buf = kzalloc(buf_len, GFP_KERNEL);920if (!buf)921return -ENOMEM;922923wiphy = ahvif->ah->hw->wiphy;924wiphy_lock(wiphy);925926links_map = ahvif->links_map;927for_each_set_bit(link_id, &links_map,928IEEE80211_MLD_MAX_NUM_LINKS) {929arvif = rcu_dereference_protected(ahvif->link[link_id],930lockdep_is_held(&wiphy->mtx));931932spin_lock_bh(&arvif->link_stats_lock);933linkstat = arvif->link_stats;934spin_unlock_bh(&arvif->link_stats_lock);935936len += scnprintf(buf + len, buf_len - len,937"link[%d] Tx Unicast Frames Enqueued = %d\n",938link_id, linkstat.tx_enqueued);939len += scnprintf(buf + len, buf_len - len,940"link[%d] Tx Broadcast Frames Enqueued = %d\n",941link_id, linkstat.tx_bcast_mcast);942len += scnprintf(buf + len, buf_len - len,943"link[%d] Tx Frames Completed = %d\n",944link_id, linkstat.tx_completed);945len += scnprintf(buf + len, buf_len - len,946"link[%d] Tx Frames Dropped = %d\n",947link_id, linkstat.tx_dropped);948949len += scnprintf(buf + len, buf_len - len,950"link[%d] Tx Frame descriptor Encap Type = ",951link_id);952953len += scnprintf(buf + len, buf_len - len,954" raw:%d",955linkstat.tx_encap_type[0]);956957len += scnprintf(buf + len, buf_len - len,958" native_wifi:%d",959linkstat.tx_encap_type[1]);960961len += scnprintf(buf + len, buf_len - len,962" ethernet:%d",963linkstat.tx_encap_type[2]);964965len += scnprintf(buf + len, buf_len - len,966"\nlink[%d] Tx Frame descriptor Encrypt Type = ",967link_id);968969for (i = 0; i < HAL_ENCRYPT_TYPE_MAX; i++) {970len += scnprintf(buf + len, buf_len - len,971" %d:%d", i,972linkstat.tx_encrypt_type[i]);973}974len += scnprintf(buf + len, buf_len - len,975"\nlink[%d] Tx Frame descriptor Type = buffer:%d extension:%d\n",976link_id, linkstat.tx_desc_type[0],977linkstat.tx_desc_type[1]);978979len += scnprintf(buf + len, buf_len - len,980"------------------------------------------------------\n");981}982983wiphy_unlock(wiphy);984985file->private_data = buf;986987return 0;988}989990static int ath12k_release_link_stats(struct inode *inode, struct file *file)991{992kfree(file->private_data);993return 0;994}995996static ssize_t ath12k_read_link_stats(struct file *file,997char __user *user_buf,998size_t count, loff_t *ppos)999{1000const char *buf = file->private_data;1001size_t len = strlen(buf);10021003return simple_read_from_buffer(user_buf, count, ppos, buf, len);1004}10051006static const struct file_operations ath12k_fops_link_stats = {1007.open = ath12k_open_link_stats,1008.release = ath12k_release_link_stats,1009.read = ath12k_read_link_stats,1010.owner = THIS_MODULE,1011.llseek = default_llseek,1012};10131014void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,1015struct ieee80211_vif *vif)1016{1017struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);10181019debugfs_create_file("link_stats", 0400, vif->debugfs_dir, ahvif,1020&ath12k_fops_link_stats);1021}10221023static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,1024char __user *user_buf,1025size_t count, loff_t *ppos)1026{1027struct ath12k_base *ab = file->private_data;1028struct ath12k_device_dp_stats *device_stats = &ab->device_stats;1029int len = 0, i, j, ret;1030struct ath12k *ar;1031const int size = 4096;1032static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {1033[HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR] = "Overflow",1034[HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR] = "MPDU len",1035[HAL_REO_ENTR_RING_RXDMA_ECODE_FCS_ERR] = "FCS",1036[HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR] = "Decrypt",1037[HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR] = "TKIP MIC",1038[HAL_REO_ENTR_RING_RXDMA_ECODE_UNECRYPTED_ERR] = "Unencrypt",1039[HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LEN_ERR] = "MSDU len",1040[HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LIMIT_ERR] = "MSDU limit",1041[HAL_REO_ENTR_RING_RXDMA_ECODE_WIFI_PARSE_ERR] = "WiFi parse",1042[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_PARSE_ERR] = "AMSDU parse",1043[HAL_REO_ENTR_RING_RXDMA_ECODE_SA_TIMEOUT_ERR] = "SA timeout",1044[HAL_REO_ENTR_RING_RXDMA_ECODE_DA_TIMEOUT_ERR] = "DA timeout",1045[HAL_REO_ENTR_RING_RXDMA_ECODE_FLOW_TIMEOUT_ERR] = "Flow timeout",1046[HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR] = "Flush req",1047[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_FRAG_ERR] = "AMSDU frag",1048[HAL_REO_ENTR_RING_RXDMA_ECODE_MULTICAST_ECHO_ERR] = "Multicast echo",1049[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_MISMATCH_ERR] = "AMSDU mismatch",1050[HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR] = "Unauth WDS",1051[HAL_REO_ENTR_RING_RXDMA_ECODE_GRPCAST_AMSDU_WDS_ERR] = "AMSDU or WDS"};10521053static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {1054[HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO] = "Desc addr zero",1055[HAL_REO_DEST_RING_ERROR_CODE_DESC_INVALID] = "Desc inval",1056[HAL_REO_DEST_RING_ERROR_CODE_AMPDU_IN_NON_BA] = "AMPDU in non BA",1057[HAL_REO_DEST_RING_ERROR_CODE_NON_BA_DUPLICATE] = "Non BA dup",1058[HAL_REO_DEST_RING_ERROR_CODE_BA_DUPLICATE] = "BA dup",1059[HAL_REO_DEST_RING_ERROR_CODE_FRAME_2K_JUMP] = "Frame 2k jump",1060[HAL_REO_DEST_RING_ERROR_CODE_BAR_2K_JUMP] = "BAR 2k jump",1061[HAL_REO_DEST_RING_ERROR_CODE_FRAME_OOR] = "Frame OOR",1062[HAL_REO_DEST_RING_ERROR_CODE_BAR_OOR] = "BAR OOR",1063[HAL_REO_DEST_RING_ERROR_CODE_NO_BA_SESSION] = "No BA session",1064[HAL_REO_DEST_RING_ERROR_CODE_FRAME_SN_EQUALS_SSN] = "Frame SN equal SSN",1065[HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED] = "PN check fail",1066[HAL_REO_DEST_RING_ERROR_CODE_2K_ERR_FLAG_SET] = "2k err",1067[HAL_REO_DEST_RING_ERROR_CODE_PN_ERR_FLAG_SET] = "PN err",1068[HAL_REO_DEST_RING_ERROR_CODE_DESC_BLOCKED] = "Desc blocked"};10691070static const char *wbm_rel_src[HAL_WBM_REL_SRC_MODULE_MAX] = {1071[HAL_WBM_REL_SRC_MODULE_TQM] = "TQM",1072[HAL_WBM_REL_SRC_MODULE_RXDMA] = "Rxdma",1073[HAL_WBM_REL_SRC_MODULE_REO] = "Reo",1074[HAL_WBM_REL_SRC_MODULE_FW] = "FW",1075[HAL_WBM_REL_SRC_MODULE_SW] = "SW"};10761077char *buf __free(kfree) = kzalloc(size, GFP_KERNEL);10781079if (!buf)1080return -ENOMEM;10811082len += scnprintf(buf + len, size - len, "DEVICE RX STATS:\n\n");1083len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",1084device_stats->err_ring_pkts);1085len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",1086device_stats->invalid_rbm);1087len += scnprintf(buf + len, size - len, "RXDMA errors:\n");10881089for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)1090len += scnprintf(buf + len, size - len, "%s: %u\n",1091rxdma_err[i], device_stats->rxdma_error[i]);10921093len += scnprintf(buf + len, size - len, "\nREO errors:\n");10941095for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)1096len += scnprintf(buf + len, size - len, "%s: %u\n",1097reo_err[i], device_stats->reo_error[i]);10981099len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");11001101for (i = 0; i < DP_REO_DST_RING_MAX; i++)1102len += scnprintf(buf + len, size - len,1103"ring%d: %u\n", i,1104device_stats->hal_reo_error[i]);11051106len += scnprintf(buf + len, size - len, "\nDEVICE TX STATS:\n");1107len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");11081109for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)1110len += scnprintf(buf + len, size - len, "ring%d: %u\n",1111i, device_stats->tx_err.desc_na[i]);11121113len += scnprintf(buf + len, size - len,1114"\nMisc Transmit Failures: %d\n",1115atomic_read(&device_stats->tx_err.misc_fail));11161117len += scnprintf(buf + len, size - len, "\ntx_wbm_rel_source:");11181119for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++)1120len += scnprintf(buf + len, size - len, " %d:%u",1121i, device_stats->tx_wbm_rel_source[i]);11221123len += scnprintf(buf + len, size - len, "\n");11241125len += scnprintf(buf + len, size - len, "\ntqm_rel_reason:");11261127for (i = 0; i < MAX_TQM_RELEASE_REASON; i++)1128len += scnprintf(buf + len, size - len, " %d:%u",1129i, device_stats->tqm_rel_reason[i]);11301131len += scnprintf(buf + len, size - len, "\n");11321133len += scnprintf(buf + len, size - len, "\nfw_tx_status:");11341135for (i = 0; i < MAX_FW_TX_STATUS; i++)1136len += scnprintf(buf + len, size - len, " %d:%u",1137i, device_stats->fw_tx_status[i]);11381139len += scnprintf(buf + len, size - len, "\n");11401141len += scnprintf(buf + len, size - len, "\ntx_enqueued:");11421143for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)1144len += scnprintf(buf + len, size - len, " %d:%u", i,1145device_stats->tx_enqueued[i]);11461147len += scnprintf(buf + len, size - len, "\n");11481149len += scnprintf(buf + len, size - len, "\ntx_completed:");11501151for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)1152len += scnprintf(buf + len, size - len, " %d:%u",1153i, device_stats->tx_completed[i]);11541155len += scnprintf(buf + len, size - len, "\n");11561157for (i = 0; i < ab->num_radios; i++) {1158ar = ath12k_mac_get_ar_by_pdev_id(ab, DP_SW2HW_MACID(i));1159if (ar) {1160len += scnprintf(buf + len, size - len,1161"\nradio%d tx_pending: %u\n", i,1162atomic_read(&ar->dp.num_tx_pending));1163}1164}11651166len += scnprintf(buf + len, size - len, "\nREO Rx Received:\n");11671168for (i = 0; i < DP_REO_DST_RING_MAX; i++) {1169len += scnprintf(buf + len, size - len, "Ring%d:", i + 1);11701171for (j = 0; j < ATH12K_MAX_DEVICES; j++) {1172len += scnprintf(buf + len, size - len,1173"\t%d:%u", j,1174device_stats->reo_rx[i][j]);1175}11761177len += scnprintf(buf + len, size - len, "\n");1178}11791180len += scnprintf(buf + len, size - len, "\nREO excep MSDU buf type:%u\n",1181device_stats->reo_excep_msdu_buf_type);11821183len += scnprintf(buf + len, size - len, "\nRx WBM REL SRC Errors:\n");11841185for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++) {1186len += scnprintf(buf + len, size - len, "%s:", wbm_rel_src[i]);11871188for (j = 0; j < ATH12K_MAX_DEVICES; j++) {1189len += scnprintf(buf + len,1190size - len,1191"\t%d:%u", j,1192device_stats->rx_wbm_rel_source[i][j]);1193}11941195len += scnprintf(buf + len, size - len, "\n");1196}11971198ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);11991200return ret;1201}12021203static const struct file_operations fops_device_dp_stats = {1204.read = ath12k_debugfs_dump_device_dp_stats,1205.open = simple_open,1206.owner = THIS_MODULE,1207.llseek = default_llseek,1208};12091210void ath12k_debugfs_pdev_create(struct ath12k_base *ab)1211{1212debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,1213&fops_simulate_fw_crash);12141215debugfs_create_file("device_dp_stats", 0400, ab->debugfs_soc, ab,1216&fops_device_dp_stats);1217}12181219void ath12k_debugfs_soc_create(struct ath12k_base *ab)1220{1221bool dput_needed;1222char soc_name[64] = {};1223struct dentry *debugfs_ath12k;12241225debugfs_ath12k = debugfs_lookup("ath12k", NULL);1226if (debugfs_ath12k) {1227/* a dentry from lookup() needs dput() after we don't use it */1228dput_needed = true;1229} else {1230debugfs_ath12k = debugfs_create_dir("ath12k", NULL);1231if (IS_ERR_OR_NULL(debugfs_ath12k))1232return;1233dput_needed = false;1234}12351236scnprintf(soc_name, sizeof(soc_name), "%s-%s", ath12k_bus_str(ab->hif.bus),1237dev_name(ab->dev));12381239ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath12k);12401241if (dput_needed)1242dput(debugfs_ath12k);1243}12441245void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)1246{1247debugfs_remove_recursive(ab->debugfs_soc);1248ab->debugfs_soc = NULL;1249/* We are not removing ath12k directory on purpose, even if it1250* would be empty. This simplifies the directory handling and it's1251* a minor cosmetic issue to leave an empty ath12k directory to1252* debugfs.1253*/1254}12551256static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)1257{1258struct ath12k *ar = inode->i_private;1259struct ath12k_fw_stats_req_params param;1260struct ath12k_hw *ah = ath12k_ar_to_ah(ar);1261int ret;12621263guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);12641265if (!ah)1266return -ENETDOWN;12671268if (ah->state != ATH12K_HW_STATE_ON)1269return -ENETDOWN;12701271void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);1272if (!buf)1273return -ENOMEM;12741275param.pdev_id = ath12k_mac_get_target_pdev_id(ar);1276/* VDEV stats is always sent for all active VDEVs from FW */1277param.vdev_id = 0;1278param.stats_id = WMI_REQUEST_VDEV_STAT;12791280ret = ath12k_mac_get_fw_stats(ar, ¶m);1281if (ret) {1282ath12k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);1283return ret;1284}12851286ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,1287buf);1288ath12k_fw_stats_reset(ar);12891290file->private_data = no_free_ptr(buf);12911292return 0;1293}12941295static int ath12k_release_vdev_stats(struct inode *inode, struct file *file)1296{1297kfree(file->private_data);12981299return 0;1300}13011302static ssize_t ath12k_read_vdev_stats(struct file *file,1303char __user *user_buf,1304size_t count, loff_t *ppos)1305{1306const char *buf = file->private_data;1307size_t len = strlen(buf);13081309return simple_read_from_buffer(user_buf, count, ppos, buf, len);1310}13111312static const struct file_operations fops_vdev_stats = {1313.open = ath12k_open_vdev_stats,1314.release = ath12k_release_vdev_stats,1315.read = ath12k_read_vdev_stats,1316.owner = THIS_MODULE,1317.llseek = default_llseek,1318};13191320static int ath12k_open_bcn_stats(struct inode *inode, struct file *file)1321{1322struct ath12k *ar = inode->i_private;1323struct ath12k_link_vif *arvif;1324struct ath12k_fw_stats_req_params param;1325struct ath12k_hw *ah = ath12k_ar_to_ah(ar);1326int ret;13271328guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);13291330if (ah && ah->state != ATH12K_HW_STATE_ON)1331return -ENETDOWN;13321333void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);1334if (!buf)1335return -ENOMEM;13361337param.pdev_id = ath12k_mac_get_target_pdev_id(ar);1338param.stats_id = WMI_REQUEST_BCN_STAT;13391340/* loop all active VDEVs for bcn stats */1341list_for_each_entry(arvif, &ar->arvifs, list) {1342if (!arvif->is_up)1343continue;13441345param.vdev_id = arvif->vdev_id;1346ret = ath12k_mac_get_fw_stats(ar, ¶m);1347if (ret) {1348ath12k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);1349return ret;1350}1351}13521353ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,1354buf);1355ath12k_fw_stats_reset(ar);13561357file->private_data = no_free_ptr(buf);13581359return 0;1360}13611362static int ath12k_release_bcn_stats(struct inode *inode, struct file *file)1363{1364kfree(file->private_data);13651366return 0;1367}13681369static ssize_t ath12k_read_bcn_stats(struct file *file,1370char __user *user_buf,1371size_t count, loff_t *ppos)1372{1373const char *buf = file->private_data;1374size_t len = strlen(buf);13751376return simple_read_from_buffer(user_buf, count, ppos, buf, len);1377}13781379static const struct file_operations fops_bcn_stats = {1380.open = ath12k_open_bcn_stats,1381.release = ath12k_release_bcn_stats,1382.read = ath12k_read_bcn_stats,1383.owner = THIS_MODULE,1384.llseek = default_llseek,1385};13861387static int ath12k_open_pdev_stats(struct inode *inode, struct file *file)1388{1389struct ath12k *ar = inode->i_private;1390struct ath12k_hw *ah = ath12k_ar_to_ah(ar);1391struct ath12k_base *ab = ar->ab;1392struct ath12k_fw_stats_req_params param;1393int ret;13941395guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);13961397if (ah && ah->state != ATH12K_HW_STATE_ON)1398return -ENETDOWN;13991400void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);1401if (!buf)1402return -ENOMEM;14031404param.pdev_id = ath12k_mac_get_target_pdev_id(ar);1405param.vdev_id = 0;1406param.stats_id = WMI_REQUEST_PDEV_STAT;14071408ret = ath12k_mac_get_fw_stats(ar, ¶m);1409if (ret) {1410ath12k_warn(ab, "failed to request fw pdev stats: %d\n", ret);1411return ret;1412}14131414ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,1415buf);1416ath12k_fw_stats_reset(ar);14171418file->private_data = no_free_ptr(buf);14191420return 0;1421}14221423static int ath12k_release_pdev_stats(struct inode *inode, struct file *file)1424{1425kfree(file->private_data);14261427return 0;1428}14291430static ssize_t ath12k_read_pdev_stats(struct file *file,1431char __user *user_buf,1432size_t count, loff_t *ppos)1433{1434const char *buf = file->private_data;1435size_t len = strlen(buf);14361437return simple_read_from_buffer(user_buf, count, ppos, buf, len);1438}14391440static const struct file_operations fops_pdev_stats = {1441.open = ath12k_open_pdev_stats,1442.release = ath12k_release_pdev_stats,1443.read = ath12k_read_pdev_stats,1444.owner = THIS_MODULE,1445.llseek = default_llseek,1446};14471448static1449void ath12k_debugfs_fw_stats_register(struct ath12k *ar)1450{1451struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",1452ar->debug.debugfs_pdev);14531454/* all stats debugfs files created are under "fw_stats" directory1455* created per PDEV1456*/1457debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,1458&fops_vdev_stats);1459debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,1460&fops_bcn_stats);1461debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,1462&fops_pdev_stats);14631464ath12k_fw_stats_init(ar);1465}14661467void ath12k_debugfs_register(struct ath12k *ar)1468{1469struct ath12k_base *ab = ar->ab;1470struct ieee80211_hw *hw = ar->ah->hw;1471char pdev_name[5];1472char buf[100] = {};14731474scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);14751476ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);14771478/* Create a symlink under ieee80211/phy* */1479scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev);1480ar->debug.debugfs_pdev_symlink = debugfs_create_symlink("ath12k",1481hw->wiphy->debugfsdir,1482buf);14831484if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) {1485debugfs_create_file("dfs_simulate_radar", 0200,1486ar->debug.debugfs_pdev, ar,1487&fops_simulate_radar);1488}14891490debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_pdev, ar,1491&fops_tpc_stats);1492debugfs_create_file("tpc_stats_type", 0200, ar->debug.debugfs_pdev,1493ar, &fops_tpc_stats_type);1494init_completion(&ar->debug.tpc_complete);14951496ath12k_debugfs_htt_stats_register(ar);1497ath12k_debugfs_fw_stats_register(ar);14981499debugfs_create_file("ext_rx_stats", 0644,1500ar->debug.debugfs_pdev, ar,1501&fops_extd_rx_stats);1502}15031504void ath12k_debugfs_unregister(struct ath12k *ar)1505{1506if (!ar->debug.debugfs_pdev)1507return;15081509/* Remove symlink under ieee80211/phy* */1510debugfs_remove(ar->debug.debugfs_pdev_symlink);1511debugfs_remove_recursive(ar->debug.debugfs_pdev);1512ar->debug.debugfs_pdev_symlink = NULL;1513ar->debug.debugfs_pdev = NULL;1514}151515161517