[PATCH v4 2/2] wifi: ath12k: Add Support to Calculate and Display TPC Values
Aditya Kumar Singh
aditya.kumar.singh at oss.qualcomm.com
Mon Jan 27 21:08:41 PST 2025
On 1/27/25 13:02, Roopni Devanathan wrote:
> From: Sowmiya Sree Elavalagan <quic_ssreeela at quicinc.com>
>
> Transmit Power Control(TPC) stats should display per chain TPC value per
> radio. Add debugfs support to read and display TPC stats type and TPC
> stats. Take power values for each preamble type, rate and NSS combination
> from a particular index from each power arrays based on number of chains,
> NSS, modes, MCS and tx beamforming enabled/disabled parameters. Minimum
> of the values taken from reg power table, rates and Conformance Test
> Limit(CTL) array table should give the TPC which is in 0.25 dBm steps.
>
> Sample Output:
> -------------
> echo 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/tpc_stats_type
> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/tpc_stats
>
> *************** TPC config **************
> * powers are in 0.25 dBm steps
> reg domain-22 chan freq-5955
> power limit-126 max reg-domain Power-252
> No.of tx chain-4 No.of rates-1164
> **************** SU WITH TXBF ****************
> TPC values for Active chains
> Rate idx Preamble Rate code 1-Chain 2-Chain 3-Chain 4-Chain
> 4 OFDM 0x000 39 15 1 -9
> 5 OFDM 0x001 39 15 1 -9
> .....
> 12 HT20 0x200 40 16 2 -8
> 13 HT20 0x201 40 16 2 -8
> .....
> 44 HT40 0x200 88 88 88 88
> 45 HT40 0x201 88 88 88 88
> .....
> 76 VHT20 0x300 40 16 2 -8
> 77 VHT20 0x301 40 16 2 -8
> .....
> 172 VHT40 0x300 88 88 88 88
> 173 VHT40 0x301 88 88 88 88
> .....
> 412 HE20 0x400 88 88 88 88
> 413 HE20 0x401 88 88 88 88
> .....
> 508 HE40 0x400 76 76 76 76
> 509 HE40 0x401 76 76 76 76
> .....
> 748 EHT20 0x50e 88 88 88 88
> 749 EHT20 0x50f 88 88 88 88
> .....
> 812 EHT40 0x50e 88 88 88 88
> 813 EHT40 0x50f 88 88 88 88
> .....
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela at quicinc.com>
> Co-developed-by: Ramya Gnanasekar <quic_rgnanase at quicinc.com>
> Signed-off-by: Ramya Gnanasekar <quic_rgnanase at quicinc.com>
> Co-developed-by: Roopni Devanathan <quic_rdevanat at quicinc.com>
> Signed-off-by: Roopni Devanathan <quic_rdevanat at quicinc.com>
> ---
> drivers/net/wireless/ath/ath12k/debugfs.c | 619 ++++++++++++++++++++++
> drivers/net/wireless/ath/ath12k/debugfs.h | 86 ++-
> drivers/net/wireless/ath/ath12k/wmi.h | 1 +
> 3 files changed, 703 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
> index 8ddcae01a2a1..51c479e0a26f 100644
> --- a/drivers/net/wireless/ath/ath12k/debugfs.c
> +++ b/drivers/net/wireless/ath/ath12k/debugfs.c
[..]
> +
> +static s16 ath12k_tpc_get_rate(struct ath12k *ar,
> + struct wmi_tpc_stats_info *tpc_stats,
> + u32 rate_idx, u32 num_chains, u32 rate_code,
> + enum wmi_tpc_pream_bw pream_bw,
> + enum wmi_halphy_ctrl_path_stats_id type,
> + u32 eht_rate_idx)
> +{
> + u32 tot_nss, tot_modes, txbf_on_off, index_offset1, index_offset2, index_offset3;
> + u8 chain_idx, stm_idx, num_streams;
> + bool is_mu, txbf_enabled = 0;
> + s8 rates_ctl_min, tpc_ctl;
> + s16 rates, tpc, reg_pwr;
> + u16 rate1, rate2;
> + int mode, ret;
> +
> + num_streams = 1 + ATH12K_HW_NSS(rate_code);
> + chain_idx = num_chains - 1;
> + stm_idx = num_streams - 1;
> + mode = -1;
> +
> + ret = ath12k_get_tpc_ctl_mode_idx(tpc_stats, pream_bw, &mode);
> + if (ret) {
> + ath12k_warn(ar->ab, "Invalid mode index received\n");
> + tpc = TPC_INVAL;
> + goto out;
> + }
> +
> + if (num_chains < num_streams) {
> + tpc = TPC_INVAL;
> + goto out;
> + }
> +
> + if (le32_to_cpu(tpc_stats->tpc_config.num_tx_chain) <= 1) {
> + tpc = TPC_INVAL;
> + goto out;
> + }
> +
> + if (type == WMI_HALPHY_PDEV_TX_SUTXBF_STATS ||
> + type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS)
> + txbf_enabled = 1;
> +
> + if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
> + type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
> + is_mu = true;
> + } else {
> + is_mu = false;
> + }
> +
> + /* Below is the min calculation of ctl array, rates array and
> + * regulator power table. tpc is minimum of all 3
> + */
> + if (pream_bw >= WMI_TPC_PREAM_EHT20 && pream_bw <= WMI_TPC_PREAM_EHT320) {
> + rate2 = tpc_stats->rates_array2.rate_array[eht_rate_idx];
> + if (is_mu)
> + rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_MU);
> + else
> + rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_SU);
> + } else {
> + rate1 = tpc_stats->rates_array1.rate_array[rate_idx];
> + if (is_mu)
> + rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_MU);
> + else
> + rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_SU);
> + }
> +
> + if (tpc_stats->tlvs_rcvd & WMI_TPC_CTL_PWR_ARRAY) {
> + tot_nss = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d1);
> + tot_modes = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d2);
> + txbf_on_off = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d3);
> + index_offset1 = txbf_on_off * tot_modes * tot_nss;
> + index_offset2 = tot_modes * tot_nss;
> + index_offset3 = tot_nss;
> +
> + tpc_ctl = *(tpc_stats->ctl_array.ctl_pwr_table +
> + chain_idx * index_offset1 + txbf_enabled * index_offset2
> + + mode * index_offset3 + stm_idx);
> + } else {
> + tpc_ctl = TPC_MAX;
> + ath12k_info(ar->ab,
> + "ctl array for tpc stats not received from fw\n");
Extra noise? Can this be under some debug mask? Is this fatal enough to
show to user always?
> + }
> +
> + rates_ctl_min = min_t(s16, rates, tpc_ctl);
> +
> + reg_pwr = tpc_stats->max_reg_allowed_power.reg_pwr_array[chain_idx];
> +
> + if (reg_pwr < 0)
> + reg_pwr = TPC_INVAL;
> +
> + tpc = min_t(s16, rates_ctl_min, reg_pwr);
> +
> + /* MODULATION_LIMIT is the maximum power limit,tpc should not exceed
> + * modulation limit even if min tpc of all three array is greater
> + * modulation limit
> + */
> + tpc = min_t(s16, tpc, MODULATION_LIMIT);
> +
> +out:
> + return tpc;
> +}
> +
> +static u16 ath12k_get_ratecode(u16 pream_idx, u16 nss, u16 mcs_rate)
> +{
> + u16 mode_type = ~0;
> +
> + /* Below assignments are just for printing purpose only */
> + switch (pream_idx) {
> + case WMI_TPC_PREAM_CCK:
> + mode_type = WMI_RATE_PREAMBLE_CCK;
> + break;
> + case WMI_TPC_PREAM_OFDM:
> + mode_type = WMI_RATE_PREAMBLE_OFDM;
> + break;
> + case WMI_TPC_PREAM_HT20:
> + case WMI_TPC_PREAM_HT40:
> + mode_type = WMI_RATE_PREAMBLE_HT;
> + break;
> + case WMI_TPC_PREAM_VHT20:
> + case WMI_TPC_PREAM_VHT40:
> + case WMI_TPC_PREAM_VHT80:
> + case WMI_TPC_PREAM_VHT160:
> + mode_type = WMI_RATE_PREAMBLE_VHT;
> + break;
> + case WMI_TPC_PREAM_HE20:
> + case WMI_TPC_PREAM_HE40:
> + case WMI_TPC_PREAM_HE80:
> + case WMI_TPC_PREAM_HE160:
> + mode_type = WMI_RATE_PREAMBLE_HE;
> + break;
> + case WMI_TPC_PREAM_EHT20:
> + case WMI_TPC_PREAM_EHT40:
> + case WMI_TPC_PREAM_EHT60:
> + case WMI_TPC_PREAM_EHT80:
> + case WMI_TPC_PREAM_EHT120:
> + case WMI_TPC_PREAM_EHT140:
> + case WMI_TPC_PREAM_EHT160:
> + case WMI_TPC_PREAM_EHT200:
> + case WMI_TPC_PREAM_EHT240:
> + case WMI_TPC_PREAM_EHT280:
> + case WMI_TPC_PREAM_EHT320:
> + mode_type = WMI_RATE_PREAMBLE_EHT;
> + if (mcs_rate == 0 || mcs_rate == 1)
> + mcs_rate += 14;
> + else
> + mcs_rate -= 2;
> + break;
> + default:
> + return mode_type;
> + }
> + return ((mode_type << 8) | ((nss & 0x7) << 5) | (mcs_rate & 0x1F));
> +}
> +
> +static bool ath12k_he_supports_extra_mcs(struct ath12k *ar, int freq)
> +{
> + struct ath12k_pdev_cap *cap = &ar->pdev->cap;
> + struct ath12k_band_cap *cap_band;
> + bool extra_mcs_supported;
> +
> + if (freq <= ATH12K_2GHZ_MAX_FREQUENCY)
> + cap_band = &cap->band[NL80211_BAND_2GHZ];
> + else if (freq <= ATH12K_5GHZ_MAX_FREQUENCY)
> + cap_band = &cap->band[NL80211_BAND_5GHZ];
> + else
> + cap_band = &cap->band[NL80211_BAND_6GHZ];
> +
> + extra_mcs_supported = u32_get_bits(cap_band->he_cap_info[1],
> + HE_EXTRA_MCS_SUPPORT);
> + return extra_mcs_supported;
> +}
> +
> +static int ath12k_tpc_fill_pream(struct ath12k *ar, char *buf, int buf_len, int len,
> + enum wmi_tpc_pream_bw pream_bw, u32 max_rix,
> + int max_nss, int max_rates, int pream_type,
> + enum wmi_halphy_ctrl_path_stats_id tpc_type,
> + int rate_idx, int eht_rate_idx)
> +{
> + struct wmi_tpc_stats_info *tpc_stats = ar->debug.tpc_stats;
> + int nss, rates, chains;
> + u8 active_tx_chains;
> + u16 rate_code;
> + s16 tpc;
> +
> + static const char *const pream_str[] = {
> + [WMI_TPC_PREAM_CCK] = "CCK",
> + [WMI_TPC_PREAM_OFDM] = "OFDM",
> + [WMI_TPC_PREAM_HT20] = "HT20",
> + [WMI_TPC_PREAM_HT40] = "HT40",
> + [WMI_TPC_PREAM_VHT20] = "VHT20",
> + [WMI_TPC_PREAM_VHT40] = "VHT40",
> + [WMI_TPC_PREAM_VHT80] = "VHT80",
> + [WMI_TPC_PREAM_VHT160] = "VHT160",
> + [WMI_TPC_PREAM_HE20] = "HE20",
> + [WMI_TPC_PREAM_HE40] = "HE40",
> + [WMI_TPC_PREAM_HE80] = "HE80",
> + [WMI_TPC_PREAM_HE160] = "HE160",
> + [WMI_TPC_PREAM_EHT20] = "EHT20",
> +
why this extra line break?
> + [WMI_TPC_PREAM_EHT40] = "EHT40",
> + [WMI_TPC_PREAM_EHT60] = "EHT60",
> + [WMI_TPC_PREAM_EHT80] = "EHT80",
> + [WMI_TPC_PREAM_EHT120] = "EHT120",
> + [WMI_TPC_PREAM_EHT140] = "EHT140",
> + [WMI_TPC_PREAM_EHT160] = "EHT160",
> + [WMI_TPC_PREAM_EHT200] = "EHT200",
> + [WMI_TPC_PREAM_EHT240] = "EHT240",
> + [WMI_TPC_PREAM_EHT280] = "EHT280",
> + [WMI_TPC_PREAM_EHT320] = "EHT320"};
> +
> + active_tx_chains = ar->num_tx_chains;
> +
> + for (nss = 0; nss < max_nss; nss++) {
> + for (rates = 0; rates < max_rates; rates++, rate_idx++, max_rix++) {
> + /* FW send extra MCS(10&11) for VHT and HE rates,
> + * this is not used. Hence skipping it here
> + */
> + if (pream_type == WMI_RATE_PREAMBLE_VHT &&
> + rates > ATH12K_VHT_MCS_MAX)
> + continue;
> +
> + if (pream_type == WMI_RATE_PREAMBLE_HE &&
> + rates > ATH12K_HE_MCS_MAX)
> + continue;
> +
> + if (pream_type == WMI_RATE_PREAMBLE_EHT &&
> + rates > ATH12K_EHT_MCS_MAX)
> + continue;
> +
> + rate_code = ath12k_get_ratecode(pream_bw, nss, rates);
> + len += scnprintf(buf + len, buf_len - len,
> + "%d\t %s\t 0x%03x\t", max_rix,
> + pream_str[pream_bw], rate_code);
Align with previous ( ?
> +
> + for (chains = 0; chains < active_tx_chains; chains++) {
> + if (nss > chains) {
> + len += scnprintf(buf + len,
> + buf_len - len,
> + "\t%s", "NA");
> + } else {
> + tpc = ath12k_tpc_get_rate(ar, tpc_stats, rate_idx,
> + chains + 1, rate_code,
> + pream_bw, tpc_type,
> + eht_rate_idx);
> +
> + if (tpc == TPC_INVAL) {
> + len += scnprintf(buf + len,
> + buf_len - len, "\tNA");
Align with previous ( ? It will fit 90 chars width.
> + } else {
> + len += scnprintf(buf + len,
> + buf_len - len, "\t%d",
> + tpc);
Align with previous ( ? It will fit 90 chars width.
> + }
> + }
> + }
> + len += scnprintf(buf + len, buf_len - len, "\n");
> +
> + if (pream_type == WMI_RATE_PREAMBLE_EHT)
> + /*For fetching the next eht rates pwr from rates array2*/
> + ++eht_rate_idx;
> + }
> + }
> +
> + return len;
> +}
> +
> +static int ath12k_tpc_stats_print(struct ath12k *ar,
> + struct wmi_tpc_stats_info *tpc_stats,
> + char *buf, size_t len,
> + enum wmi_halphy_ctrl_path_stats_id type)
> +{
> + u32 eht_idx = 0, pream_idx = 0, rate_pream_idx = 0, total_rates = 0, max_rix = 0;
> + u32 chan_freq, num_tx_chain, caps, i, j = 1;
> + size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
> + u8 nss, active_tx_chains;
> + bool he_ext_mcs;
> + static const char *const type_str[WMI_HALPHY_PDEV_TX_STATS_MAX] = {
> + [WMI_HALPHY_PDEV_TX_SU_STATS] = "SU",
> + [WMI_HALPHY_PDEV_TX_SUTXBF_STATS] = "SU WITH TXBF",
> + [WMI_HALPHY_PDEV_TX_MU_STATS] = "MU",
> + [WMI_HALPHY_PDEV_TX_MUTXBF_STATS] = "MU WITH TXBF"};
> +
> + u8 max_rates[WMI_TPC_PREAM_MAX] = {
Others are const declared. Why not this?
> + [WMI_TPC_PREAM_CCK] = ATH12K_CCK_RATES,
> + [WMI_TPC_PREAM_OFDM] = ATH12K_OFDM_RATES,
> + [WMI_TPC_PREAM_HT20] = ATH12K_HT_RATES,
> + [WMI_TPC_PREAM_HT40] = ATH12K_HT_RATES,
> + [WMI_TPC_PREAM_VHT20] = ATH12K_VHT_RATES,
> + [WMI_TPC_PREAM_VHT40] = ATH12K_VHT_RATES,
> + [WMI_TPC_PREAM_VHT80] = ATH12K_VHT_RATES,
> + [WMI_TPC_PREAM_VHT160] = ATH12K_VHT_RATES,
> + [WMI_TPC_PREAM_HE20] = ATH12K_HE_RATES,
> + [WMI_TPC_PREAM_HE40] = ATH12K_HE_RATES,
> + [WMI_TPC_PREAM_HE80] = ATH12K_HE_RATES,
> + [WMI_TPC_PREAM_HE160] = ATH12K_HE_RATES,
> + [WMI_TPC_PREAM_EHT20] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT40] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT60] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT80] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT120] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT140] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT160] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT200] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT240] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT280] = ATH12K_EHT_RATES,
> + [WMI_TPC_PREAM_EHT320] = ATH12K_EHT_RATES};
> + static const u8 max_nss[WMI_TPC_PREAM_MAX] = {
> + [WMI_TPC_PREAM_CCK] = ATH12K_NSS_1,
> + [WMI_TPC_PREAM_OFDM] = ATH12K_NSS_1,
> + [WMI_TPC_PREAM_HT20] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_HT40] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_VHT20] = ATH12K_NSS_8,
> + [WMI_TPC_PREAM_VHT40] = ATH12K_NSS_8,
> + [WMI_TPC_PREAM_VHT80] = ATH12K_NSS_8,
> + [WMI_TPC_PREAM_VHT160] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_HE20] = ATH12K_NSS_8,
> + [WMI_TPC_PREAM_HE40] = ATH12K_NSS_8,
> + [WMI_TPC_PREAM_HE80] = ATH12K_NSS_8,
> + [WMI_TPC_PREAM_HE160] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT20] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT40] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT60] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT80] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT120] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT140] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT160] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT200] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT240] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT280] = ATH12K_NSS_4,
> + [WMI_TPC_PREAM_EHT320] = ATH12K_NSS_4};
> +
> + u16 rate_idx[WMI_TPC_PREAM_MAX] = {0},
> + eht_rate_idx[WMI_TPC_PREAM_MAX] = {0};
nit: prefer {} over {0} ?
> + static const u8 pream_type[WMI_TPC_PREAM_MAX] = {
> + [WMI_TPC_PREAM_CCK] = WMI_RATE_PREAMBLE_CCK,
> + [WMI_TPC_PREAM_OFDM] = WMI_RATE_PREAMBLE_OFDM,
> + [WMI_TPC_PREAM_HT20] = WMI_RATE_PREAMBLE_HT,
> + [WMI_TPC_PREAM_HT40] = WMI_RATE_PREAMBLE_HT,
> + [WMI_TPC_PREAM_VHT20] = WMI_RATE_PREAMBLE_VHT,
> + [WMI_TPC_PREAM_VHT40] = WMI_RATE_PREAMBLE_VHT,
> + [WMI_TPC_PREAM_VHT80] = WMI_RATE_PREAMBLE_VHT,
> + [WMI_TPC_PREAM_VHT160] = WMI_RATE_PREAMBLE_VHT,
> + [WMI_TPC_PREAM_HE20] = WMI_RATE_PREAMBLE_HE,
> + [WMI_TPC_PREAM_HE40] = WMI_RATE_PREAMBLE_HE,
> + [WMI_TPC_PREAM_HE80] = WMI_RATE_PREAMBLE_HE,
> + [WMI_TPC_PREAM_HE160] = WMI_RATE_PREAMBLE_HE,
> + [WMI_TPC_PREAM_EHT20] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT40] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT60] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT80] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT120] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT140] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT160] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT200] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT240] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT280] = WMI_RATE_PREAMBLE_EHT,
> + [WMI_TPC_PREAM_EHT320] = WMI_RATE_PREAMBLE_EHT};
> +
> + chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);
> + num_tx_chain = le32_to_cpu(tpc_stats->tpc_config.num_tx_chain);
> + caps = le32_to_cpu(tpc_stats->tpc_config.caps);
> +
> + active_tx_chains = ar->num_tx_chains;
> + he_ext_mcs = ath12k_he_supports_extra_mcs(ar, chan_freq);
> +
> + /* mcs 12&13 is sent by FW for certain HWs in rate array, skipping it as
> + * it is not supported
> + */
> + if (he_ext_mcs) {
> + for (i = WMI_TPC_PREAM_HE20; i <= WMI_TPC_PREAM_HE160; ++i)
nit: extra space before ++i?
> + max_rates[i] = ATH12K_HE_RATES;
> + }
> +
> + if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
> + type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
> + pream_idx = WMI_TPC_PREAM_VHT20;
> +
> + for (i = WMI_TPC_PREAM_CCK; i <= WMI_TPC_PREAM_HT40; ++i)
> + max_rix += max_nss[i] * max_rates[i];
> + }
> + /* Enumerate all the rate indices */
> + for (i = rate_pream_idx + 1 ; i < WMI_TPC_PREAM_MAX; i++) {
nit: extra space before ; ?
> + nss = (max_nss[i - 1] < num_tx_chain ?
> + max_nss[i - 1] : num_tx_chain);
> +
> + rate_idx[i] = rate_idx[i - 1] + max_rates[i - 1] * nss;
> +
> + if (pream_type[i] == WMI_RATE_PREAMBLE_EHT) {
> + eht_rate_idx[j] = eht_rate_idx[j - 1] + max_rates[i] * nss;
> + ++j;
> + }
> + }
> +
> + for (i = 0 ; i < WMI_TPC_PREAM_MAX; i++) {
nit: extra space before ; ?
> + nss = (max_nss[i] < num_tx_chain ?
> + max_nss[i] : num_tx_chain);
> + total_rates += max_rates[i] * nss;
> + }
> +
> + len += scnprintf(buf + len, buf_len - len,
> + "No.of rates-%d\n", total_rates);
> +
> + len += scnprintf(buf + len, buf_len - len,
> + "**************** %s ****************\n",
> + type_str[type]);
> + len += scnprintf(buf + len, buf_len - len,
> + "\t\t\t\tTPC values for Active chains\n");
> + len += scnprintf(buf + len, buf_len - len,
> + "Rate idx Preamble Rate code");
> +
> + for (i = 1; i <= active_tx_chains; ++i) {
> + len += scnprintf(buf + len, buf_len - len,
> + "\t%d-Chain", i);
> + }
> +
> + len += scnprintf(buf + len, buf_len - len, "\n");
> + for (i = pream_idx; i < WMI_TPC_PREAM_MAX; i++) {
> + if (chan_freq <= 2483) {
> + if (i == WMI_TPC_PREAM_VHT80 ||
> + i == WMI_TPC_PREAM_VHT160 ||
> + i == WMI_TPC_PREAM_HE80 ||
> + i == WMI_TPC_PREAM_HE160 ||
> + (i >= WMI_TPC_PREAM_EHT60 &&
> + i <= WMI_TPC_PREAM_EHT320)) {
> + max_rix += max_nss[i] * max_rates[i];
> + continue;
> + }
> + } else {
> + if (i == WMI_TPC_PREAM_CCK) {
> + max_rix += max_rates[i];
> + continue;
> + }
> + }
> +
> + nss = (max_nss[i] < ar->num_tx_chains ? max_nss[i] : ar->num_tx_chains);
> +
> + if (!(caps &
> + (1 << ATH12K_TPC_STATS_SUPPORT_BE_PUNC))) {
> + if (i == WMI_TPC_PREAM_EHT60 || i == WMI_TPC_PREAM_EHT120 ||
> + i == WMI_TPC_PREAM_EHT140 || i == WMI_TPC_PREAM_EHT200 ||
> + i == WMI_TPC_PREAM_EHT240 || i == WMI_TPC_PREAM_EHT280) {
> + max_rix += max_nss[i] * max_rates[i];
> + continue;
> + }
> + }
> +
> + len = ath12k_tpc_fill_pream(ar, buf, buf_len, len, i, max_rix, nss,
> + max_rates[i], pream_type[i],
> + type, rate_idx[i], eht_rate_idx[eht_idx]);
> +
> + if (pream_type[i] == WMI_RATE_PREAMBLE_EHT)
> + /*For fetch the next index eht rates from rates array2*/
> + ++eht_idx;
> +
> + max_rix += max_nss[i] * max_rates[i];
> + }
> + return len;
> +}
> +
> +static void ath12k_tpc_stats_fill(struct ath12k *ar,
> + struct wmi_tpc_stats_info *tpc_stats,
> + char *buf)
> +{
> + size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
> + struct wmi_tpc_config_params *tpc;
> + size_t len = 0;
> +
> + spin_lock_bh(&ar->data_lock);
> + if (!tpc_stats) {
This check can be outside lock?
> + ath12k_warn(ar->ab, "failed to find tpc stats\n");
> + goto unlock;
> + }
> +
> + tpc = &tpc_stats->tpc_config;
> + len += scnprintf(buf + len, buf_len - len, "\n");
> + len += scnprintf(buf + len, buf_len - len,
> + "*************** TPC config **************\n");
> + len += scnprintf(buf + len, buf_len - len,
> + "* powers are in 0.25 dBm steps\n");
> + len += scnprintf(buf + len, buf_len - len,
> + "reg domain-%d\t\tchan freq-%d\n",
> + tpc->reg_domain, tpc->chan_freq);
> + len += scnprintf(buf + len, buf_len - len,
> + "power limit-%d\t\tmax reg-domain Power-%d\n",
> + le32_to_cpu(tpc->twice_max_reg_power) / 2, tpc->power_limit);
> + len += scnprintf(buf + len, buf_len - len,
> + "No.of tx chain-%d\t",
> + ar->num_tx_chains);
> +
> + ath12k_tpc_stats_print(ar, tpc_stats, buf, len,
> + ar->debug.tpc_stats_type);
> +
> +unlock:
> + spin_unlock_bh(&ar->data_lock);
> +}
> +
> static int ath12k_open_tpc_stats(struct inode *inode, struct file *file)
> {
> struct ath12k *ar = inode->i_private;
> @@ -91,6 +700,7 @@ static int ath12k_open_tpc_stats(struct inode *inode, struct file *file)
> return -ETIMEDOUT;
> }
>
> + ath12k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
> file->private_data = no_free_ptr(buf);
>
> spin_lock_bh(&ar->data_lock);
> @@ -125,6 +735,12 @@ static const struct file_operations fops_tpc_stats = {
> .llseek = default_llseek,
> };
>
> +static const struct file_operations fops_tpc_stats_type = {
> + .write = ath12k_write_tpc_stats_type,
> + .open = simple_open,
> + .llseek = default_llseek,
> +};
> +
> void ath12k_debugfs_soc_create(struct ath12k_base *ab)
> {
> bool dput_needed;
> @@ -563,6 +1179,9 @@ void ath12k_debugfs_register(struct ath12k *ar)
>
> debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_pdev, ar,
> &fops_tpc_stats);
> + debugfs_create_file("tpc_stats_type", 0200, ar->debug.debugfs_pdev,
> + ar, &fops_tpc_stats_type);
> + init_completion(&ar->debug.tpc_complete);
>
> ath12k_debugfs_htt_stats_register(ar);
> ath12k_debugfs_fw_stats_register(ar);
> diff --git a/drivers/net/wireless/ath/ath12k/debugfs.h b/drivers/net/wireless/ath/ath12k/debugfs.h
> index 25b5219ffe49..60c08964d883 100644
> --- a/drivers/net/wireless/ath/ath12k/debugfs.h
> +++ b/drivers/net/wireless/ath/ath12k/debugfs.h
> @@ -16,11 +16,91 @@ void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
> struct ath12k_fw_stats *stats);
> void ath12k_debugfs_fw_stats_reset(struct ath12k *ar);
>
> -#define TPC_STATS_WAIT_TIME (1 * HZ)
> -#define TPC_STATS_TOT_ROW 700
> -#define TPC_STATS_TOT_COLUMN 100
> +#define ATH12K_CCK_RATES 4
> +#define ATH12K_OFDM_RATES 8
> +#define ATH12K_HT_RATES 8
> +#define ATH12K_VHT_RATES 12
> +#define ATH12K_HE_RATES 12
> +#define ATH12K_HE_RATES_WITH_EXTRA_MCS 14
> +#define ATH12K_EHT_RATES 16
> +#define HE_EXTRA_MCS_SUPPORT GENMASK(31, 16)
> +#define ATH12K_NSS_1 1
> +#define ATH12K_NSS_4 4
> +#define ATH12K_NSS_8 8
> +#define ATH12K_HW_NSS(_rcode) (((_rcode) >> 5) & 0x7)
> +#define TPC_STATS_WAIT_TIME (1 * HZ)
> +#define MAX_TPC_PREAM_STR_LEN 7
> +#define TPC_INVAL -128
> +#define TPC_MAX 127
> +#define TPC_STATS_WAIT_TIME (1 * HZ)
> +#define TPC_STATS_TOT_ROW 700
> +#define TPC_STATS_TOT_COLUMN 100
> +#define MODULATION_LIMIT 126
> +
> +#define ATH12K_2GHZ_MAX_FREQUENCY 2495
> +#define ATH12K_5GHZ_MAX_FREQUENCY 5920
Not the correct place to have max freq macro. May be reg.h ?
> +
> #define ATH12K_TPC_STATS_BUF_SIZE (TPC_STATS_TOT_ROW * TPC_STATS_TOT_COLUMN)
>
> +enum wmi_tpc_pream_bw {
> + WMI_TPC_PREAM_CCK,
> + WMI_TPC_PREAM_OFDM,
> + WMI_TPC_PREAM_HT20,
> + WMI_TPC_PREAM_HT40,
> + WMI_TPC_PREAM_VHT20,
> + WMI_TPC_PREAM_VHT40,
> + WMI_TPC_PREAM_VHT80,
> + WMI_TPC_PREAM_VHT160,
> + WMI_TPC_PREAM_HE20,
> + WMI_TPC_PREAM_HE40,
> + WMI_TPC_PREAM_HE80,
> + WMI_TPC_PREAM_HE160,
> + WMI_TPC_PREAM_EHT20,
> + WMI_TPC_PREAM_EHT40,
> + WMI_TPC_PREAM_EHT60,
> + WMI_TPC_PREAM_EHT80,
> + WMI_TPC_PREAM_EHT120,
> + WMI_TPC_PREAM_EHT140,
> + WMI_TPC_PREAM_EHT160,
> + WMI_TPC_PREAM_EHT200,
> + WMI_TPC_PREAM_EHT240,
> + WMI_TPC_PREAM_EHT280,
> + WMI_TPC_PREAM_EHT320,
> + WMI_TPC_PREAM_MAX
> +};
> +
> +enum ath12k_debug_tpc_stats_ctl_mode {
> + ATH12K_TPC_STATS_CTL_MODE_LEGACY_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HT_VHT20_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HE_EHT20_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HT_VHT40_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HE_EHT40_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_VHT80_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HE_EHT80_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_VHT160_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HE_EHT160_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HE_EHT320_5GHZ_6GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_CCK_2GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_LEGACY_2GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HT20_2GHZ,
> + ATH12K_TPC_STATS_CTL_MODE_HT40_2GHZ,
> +
> + ATH12K_TPC_STATS_CTL_MODE_EHT80_SU_PUNC20 = 23,
> + ATH12K_TPC_STATS_CTL_MODE_EHT160_SU_PUNC20,
> + ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC40,
> + ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC80,
> + ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC120
> +};
> +
> +enum ath12k_debug_tpc_stats_support_modes {
> + ATH12K_TPC_STATS_SUPPORT_160 = 0,
> + ATH12K_TPC_STATS_SUPPORT_320,
> + ATH12K_TPC_STATS_SUPPORT_AX,
> + ATH12K_TPC_STATS_SUPPORT_AX_EXTRA_MCS,
> + ATH12K_TPC_STATS_SUPPORT_BE,
> + ATH12K_TPC_STATS_SUPPORT_BE_PUNC,
> +};
> +
> #else
> static inline void ath12k_debugfs_soc_create(struct ath12k_base *ab)
> {
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index f88f6a6bb15e..c474c46130b9 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -4640,6 +4640,7 @@ enum wmi_rate_preamble {
> WMI_RATE_PREAMBLE_HT,
> WMI_RATE_PREAMBLE_VHT,
> WMI_RATE_PREAMBLE_HE,
> + WMI_RATE_PREAMBLE_EHT,
> };
>
> /**
--
Aditya
More information about the ath12k
mailing list