257 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2021-2022 Intel Corporation4 */5 6#include <net/mac80211.h>7#include "fw/api/rs.h"8#include "iwl-drv.h"9#include "iwl-config.h"10 11#define IWL_DECLARE_RATE_INFO(r) \12 [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP13 14/*15 * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP16 * */17static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {18 IWL_DECLARE_RATE_INFO(1),19 IWL_DECLARE_RATE_INFO(2),20 IWL_DECLARE_RATE_INFO(5),21 IWL_DECLARE_RATE_INFO(11),22 IWL_DECLARE_RATE_INFO(6),23 IWL_DECLARE_RATE_INFO(9),24 IWL_DECLARE_RATE_INFO(12),25 IWL_DECLARE_RATE_INFO(18),26 IWL_DECLARE_RATE_INFO(24),27 IWL_DECLARE_RATE_INFO(36),28 IWL_DECLARE_RATE_INFO(48),29 IWL_DECLARE_RATE_INFO(54),30};31 32/* mbps, mcs */33static const struct iwl_rate_mcs_info rate_mcs[IWL_RATE_COUNT] = {34 { "1", "BPSK DSSS"},35 { "2", "QPSK DSSS"},36 {"5.5", "BPSK CCK"},37 { "11", "QPSK CCK"},38 { "6", "BPSK 1/2"},39 { "9", "BPSK 1/2"},40 { "12", "QPSK 1/2"},41 { "18", "QPSK 3/4"},42 { "24", "16QAM 1/2"},43 { "36", "16QAM 3/4"},44 { "48", "64QAM 2/3"},45 { "54", "64QAM 3/4"},46 { "60", "64QAM 5/6"},47};48 49static const char * const ant_name[] = {50 [ANT_NONE] = "None",51 [ANT_A] = "A",52 [ANT_B] = "B",53 [ANT_AB] = "AB",54};55 56static const char * const pretty_bw[] = {57 "20Mhz",58 "40Mhz",59 "80Mhz",60 "160 Mhz",61 "320Mhz",62};63 64u8 iwl_fw_rate_idx_to_plcp(int idx)65{66 return fw_rate_idx_to_plcp[idx];67}68IWL_EXPORT_SYMBOL(iwl_fw_rate_idx_to_plcp);69 70const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx)71{72 return &rate_mcs[idx];73}74IWL_EXPORT_SYMBOL(iwl_rate_mcs);75 76const char *iwl_rs_pretty_ant(u8 ant)77{78 if (ant >= ARRAY_SIZE(ant_name))79 return "UNKNOWN";80 81 return ant_name[ant];82}83IWL_EXPORT_SYMBOL(iwl_rs_pretty_ant);84 85const char *iwl_rs_pretty_bw(int bw)86{87 if (bw >= ARRAY_SIZE(pretty_bw))88 return "unknown bw";89 90 return pretty_bw[bw];91}92IWL_EXPORT_SYMBOL(iwl_rs_pretty_bw);93 94static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)95{96 int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;97 int idx;98 bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1);99 int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0;100 int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;101 102 for (idx = offset; idx < last; idx++)103 if (iwl_fw_rate_idx_to_plcp(idx) == rate)104 return idx - offset;105 return IWL_RATE_INVALID;106}107 108u32 iwl_new_rate_from_v1(u32 rate_v1)109{110 u32 rate_v2 = 0;111 u32 dup = 0;112 113 if (rate_v1 == 0)114 return rate_v1;115 /* convert rate */116 if (rate_v1 & RATE_MCS_HT_MSK_V1) {117 u32 nss = 0;118 119 rate_v2 |= RATE_MCS_HT_MSK;120 rate_v2 |=121 rate_v1 & RATE_HT_MCS_RATE_CODE_MSK_V1;122 nss = (rate_v1 & RATE_HT_MCS_MIMO2_MSK) >>123 RATE_HT_MCS_NSS_POS_V1;124 rate_v2 |= nss << RATE_MCS_NSS_POS;125 } else if (rate_v1 & RATE_MCS_VHT_MSK_V1 ||126 rate_v1 & RATE_MCS_HE_MSK_V1) {127 rate_v2 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK;128 129 rate_v2 |= rate_v1 & RATE_MCS_NSS_MSK;130 131 if (rate_v1 & RATE_MCS_HE_MSK_V1) {132 u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1;133 u32 he_type = he_type_bits >> RATE_MCS_HE_TYPE_POS_V1;134 u32 he_106t = (rate_v1 & RATE_MCS_HE_106T_MSK_V1) >>135 RATE_MCS_HE_106T_POS_V1;136 u32 he_gi_ltf = (rate_v1 & RATE_MCS_HE_GI_LTF_MSK_V1) >>137 RATE_MCS_HE_GI_LTF_POS;138 139 if ((he_type_bits == RATE_MCS_HE_TYPE_SU ||140 he_type_bits == RATE_MCS_HE_TYPE_EXT_SU) &&141 he_gi_ltf == RATE_MCS_HE_SU_4_LTF)142 /* the new rate have an additional bit to143 * represent the value 4 rather then using SGI144 * bit for this purpose - as it was done in the old145 * rate */146 he_gi_ltf += (rate_v1 & RATE_MCS_SGI_MSK_V1) >>147 RATE_MCS_SGI_POS_V1;148 149 rate_v2 |= he_gi_ltf << RATE_MCS_HE_GI_LTF_POS;150 rate_v2 |= he_type << RATE_MCS_HE_TYPE_POS;151 rate_v2 |= he_106t << RATE_MCS_HE_106T_POS;152 rate_v2 |= rate_v1 & RATE_HE_DUAL_CARRIER_MODE_MSK;153 rate_v2 |= RATE_MCS_HE_MSK;154 } else {155 rate_v2 |= RATE_MCS_VHT_MSK;156 }157 /* if legacy format */158 } else {159 u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1);160 161 if (WARN_ON_ONCE(legacy_rate == IWL_RATE_INVALID))162 legacy_rate = (rate_v1 & RATE_MCS_CCK_MSK_V1) ?163 IWL_FIRST_CCK_RATE : IWL_FIRST_OFDM_RATE;164 165 rate_v2 |= legacy_rate;166 if (!(rate_v1 & RATE_MCS_CCK_MSK_V1))167 rate_v2 |= RATE_MCS_LEGACY_OFDM_MSK;168 }169 170 /* convert flags */171 if (rate_v1 & RATE_MCS_LDPC_MSK_V1)172 rate_v2 |= RATE_MCS_LDPC_MSK;173 rate_v2 |= (rate_v1 & RATE_MCS_CHAN_WIDTH_MSK_V1) |174 (rate_v1 & RATE_MCS_ANT_AB_MSK) |175 (rate_v1 & RATE_MCS_STBC_MSK) |176 (rate_v1 & RATE_MCS_BF_MSK);177 178 dup = (rate_v1 & RATE_MCS_DUP_MSK_V1) >> RATE_MCS_DUP_POS_V1;179 if (dup) {180 rate_v2 |= RATE_MCS_DUP_MSK;181 rate_v2 |= dup << RATE_MCS_CHAN_WIDTH_POS;182 }183 184 if ((!(rate_v1 & RATE_MCS_HE_MSK_V1)) &&185 (rate_v1 & RATE_MCS_SGI_MSK_V1))186 rate_v2 |= RATE_MCS_SGI_MSK;187 188 return rate_v2;189}190IWL_EXPORT_SYMBOL(iwl_new_rate_from_v1);191 192int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)193{194 char *type;195 u8 mcs = 0, nss = 0;196 u8 ant = (rate & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS;197 u32 bw = (rate & RATE_MCS_CHAN_WIDTH_MSK) >>198 RATE_MCS_CHAN_WIDTH_POS;199 u32 format = rate & RATE_MCS_MOD_TYPE_MSK;200 bool sgi;201 202 if (format == RATE_MCS_CCK_MSK ||203 format == RATE_MCS_LEGACY_OFDM_MSK) {204 int legacy_rate = rate & RATE_LEGACY_RATE_MSK;205 int index = format == RATE_MCS_CCK_MSK ?206 legacy_rate :207 legacy_rate + IWL_FIRST_OFDM_RATE;208 209 return scnprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps",210 iwl_rs_pretty_ant(ant),211 iwl_rate_mcs(index)->mbps);212 }213 214 if (format == RATE_MCS_VHT_MSK)215 type = "VHT";216 else if (format == RATE_MCS_HT_MSK)217 type = "HT";218 else if (format == RATE_MCS_HE_MSK)219 type = "HE";220 else if (format == RATE_MCS_EHT_MSK)221 type = "EHT";222 else223 type = "Unknown"; /* shouldn't happen */224 225 mcs = format == RATE_MCS_HT_MSK ?226 RATE_HT_MCS_INDEX(rate) :227 rate & RATE_MCS_CODE_MSK;228 nss = ((rate & RATE_MCS_NSS_MSK)229 >> RATE_MCS_NSS_POS) + 1;230 sgi = format == RATE_MCS_HE_MSK ?231 iwl_he_is_sgi(rate) :232 rate & RATE_MCS_SGI_MSK;233 234 return scnprintf(buf, bufsz,235 "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s",236 rate, type, iwl_rs_pretty_ant(ant), iwl_rs_pretty_bw(bw), mcs, nss,237 (sgi) ? "SGI " : "NGI ",238 (rate & RATE_MCS_STBC_MSK) ? "STBC " : "",239 (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "",240 (rate & RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "",241 (rate & RATE_MCS_BF_MSK) ? "BF " : "");242}243IWL_EXPORT_SYMBOL(rs_pretty_print_rate);244 245bool iwl_he_is_sgi(u32 rate_n_flags)246{247 u32 type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;248 u32 ltf_gi = rate_n_flags & RATE_MCS_HE_GI_LTF_MSK;249 250 if (type == RATE_MCS_HE_TYPE_SU ||251 type == RATE_MCS_HE_TYPE_EXT_SU)252 return ltf_gi == RATE_MCS_HE_SU_4_LTF_08_GI;253 return false;254}255IWL_EXPORT_SYMBOL(iwl_he_is_sgi);256 257