| // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| /* |
| * Copyright (C) 2021-2022, 2025 Intel Corporation |
| */ |
| |
| #include <net/mac80211.h> |
| #include "fw/api/rs.h" |
| #include "iwl-drv.h" |
| #include "iwl-config.h" |
| |
| #define IWL_DECLARE_RATE_INFO(r) \ |
| [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP |
| |
| /* |
| * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP |
| * */ |
| static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = { |
| IWL_DECLARE_RATE_INFO(1), |
| IWL_DECLARE_RATE_INFO(2), |
| IWL_DECLARE_RATE_INFO(5), |
| IWL_DECLARE_RATE_INFO(11), |
| IWL_DECLARE_RATE_INFO(6), |
| IWL_DECLARE_RATE_INFO(9), |
| IWL_DECLARE_RATE_INFO(12), |
| IWL_DECLARE_RATE_INFO(18), |
| IWL_DECLARE_RATE_INFO(24), |
| IWL_DECLARE_RATE_INFO(36), |
| IWL_DECLARE_RATE_INFO(48), |
| IWL_DECLARE_RATE_INFO(54), |
| }; |
| |
| /* mbps, mcs */ |
| static const struct iwl_rate_mcs_info rate_mcs[IWL_RATE_COUNT] = { |
| { "1", "BPSK DSSS"}, |
| { "2", "QPSK DSSS"}, |
| {"5.5", "BPSK CCK"}, |
| { "11", "QPSK CCK"}, |
| { "6", "BPSK 1/2"}, |
| { "9", "BPSK 1/2"}, |
| { "12", "QPSK 1/2"}, |
| { "18", "QPSK 3/4"}, |
| { "24", "16QAM 1/2"}, |
| { "36", "16QAM 3/4"}, |
| { "48", "64QAM 2/3"}, |
| { "54", "64QAM 3/4"}, |
| { "60", "64QAM 5/6"}, |
| }; |
| |
| static const char * const ant_name[] = { |
| [ANT_NONE] = "None", |
| [ANT_A] = "A", |
| [ANT_B] = "B", |
| [ANT_AB] = "AB", |
| }; |
| |
| static const char * const pretty_bw[] = { |
| "20Mhz", |
| "40Mhz", |
| "80Mhz", |
| "160 Mhz", |
| "320Mhz", |
| }; |
| |
| u8 iwl_fw_rate_idx_to_plcp(int idx) |
| { |
| return fw_rate_idx_to_plcp[idx]; |
| } |
| IWL_EXPORT_SYMBOL(iwl_fw_rate_idx_to_plcp); |
| |
| const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx) |
| { |
| return &rate_mcs[idx]; |
| } |
| IWL_EXPORT_SYMBOL(iwl_rate_mcs); |
| |
| const char *iwl_rs_pretty_ant(u8 ant) |
| { |
| if (ant >= ARRAY_SIZE(ant_name)) |
| return "UNKNOWN"; |
| |
| return ant_name[ant]; |
| } |
| IWL_EXPORT_SYMBOL(iwl_rs_pretty_ant); |
| |
| const char *iwl_rs_pretty_bw(int bw) |
| { |
| if (bw >= ARRAY_SIZE(pretty_bw)) |
| return "unknown bw"; |
| |
| return pretty_bw[bw]; |
| } |
| IWL_EXPORT_SYMBOL(iwl_rs_pretty_bw); |
| |
| int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) |
| { |
| char *type; |
| u8 mcs = 0, nss = 0; |
| u8 ant = (rate & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS; |
| u32 bw = (rate & RATE_MCS_CHAN_WIDTH_MSK) >> |
| RATE_MCS_CHAN_WIDTH_POS; |
| u32 format = rate & RATE_MCS_MOD_TYPE_MSK; |
| int index = 0; |
| bool sgi; |
| |
| switch (format) { |
| case RATE_MCS_MOD_TYPE_LEGACY_OFDM: |
| index = IWL_FIRST_OFDM_RATE; |
| fallthrough; |
| case RATE_MCS_MOD_TYPE_CCK: |
| index += rate & RATE_LEGACY_RATE_MSK; |
| |
| return scnprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps", |
| iwl_rs_pretty_ant(ant), |
| iwl_rate_mcs(index)->mbps); |
| case RATE_MCS_MOD_TYPE_VHT: |
| type = "VHT"; |
| break; |
| case RATE_MCS_MOD_TYPE_HT: |
| type = "HT"; |
| break; |
| case RATE_MCS_MOD_TYPE_HE: |
| type = "HE"; |
| break; |
| case RATE_MCS_MOD_TYPE_EHT: |
| type = "EHT"; |
| break; |
| default: |
| type = "Unknown"; /* shouldn't happen */ |
| } |
| |
| mcs = format == RATE_MCS_MOD_TYPE_HT ? |
| RATE_HT_MCS_INDEX(rate) : |
| rate & RATE_MCS_CODE_MSK; |
| nss = u32_get_bits(rate, RATE_MCS_NSS_MSK); |
| sgi = format == RATE_MCS_MOD_TYPE_HE ? |
| iwl_he_is_sgi(rate) : |
| rate & RATE_MCS_SGI_MSK; |
| |
| return scnprintf(buf, bufsz, |
| "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s", |
| rate, type, iwl_rs_pretty_ant(ant), iwl_rs_pretty_bw(bw), mcs, nss, |
| (sgi) ? "SGI " : "NGI ", |
| (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", |
| (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", |
| (rate & RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "", |
| (rate & RATE_MCS_BF_MSK) ? "BF " : ""); |
| } |
| IWL_EXPORT_SYMBOL(rs_pretty_print_rate); |
| |
| bool iwl_he_is_sgi(u32 rate_n_flags) |
| { |
| u32 type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; |
| u32 ltf_gi = rate_n_flags & RATE_MCS_HE_GI_LTF_MSK; |
| |
| if (type == RATE_MCS_HE_TYPE_SU || |
| type == RATE_MCS_HE_TYPE_EXT_SU) |
| return ltf_gi == RATE_MCS_HE_SU_4_LTF_08_GI; |
| return false; |
| } |
| IWL_EXPORT_SYMBOL(iwl_he_is_sgi); |
| |