1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2021 Intel Corporation 4 */ 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_PLCP 13 14 /* 15 * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP 16 * */ 17 static 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 */ 33 static 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 49 static const char * const ant_name[] = { 50 [ANT_NONE] = "None", 51 [ANT_A] = "A", 52 [ANT_B] = "B", 53 [ANT_AB] = "AB", 54 }; 55 56 static const char * const pretty_bw[] = { 57 "20Mhz", 58 "40Mhz", 59 "80Mhz", 60 "160 Mhz", 61 "320Mhz", 62 }; 63 64 u8 iwl_fw_rate_idx_to_plcp(int idx) 65 { 66 return fw_rate_idx_to_plcp[idx]; 67 } 68 IWL_EXPORT_SYMBOL(iwl_fw_rate_idx_to_plcp); 69 70 const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx) 71 { 72 return &rate_mcs[idx]; 73 } 74 IWL_EXPORT_SYMBOL(iwl_rate_mcs); 75 76 const 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 } 83 IWL_EXPORT_SYMBOL(iwl_rs_pretty_ant); 84 85 const 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 } 92 IWL_EXPORT_SYMBOL(iwl_rs_pretty_bw); 93 94 static 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 108 u32 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_VHT_MCS_MIMO2_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 to 143 * represent the value 4 rather then using SGI 144 * bit for this purpose - as it was done in the old 145 * 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 } 190 IWL_EXPORT_SYMBOL(iwl_new_rate_from_v1); 191 192 int 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 index == IWL_RATE_INVALID ? "BAD" : 212 iwl_rate_mcs(index)->mbps); 213 } 214 215 if (format == RATE_MCS_VHT_MSK) 216 type = "VHT"; 217 else if (format == RATE_MCS_HT_MSK) 218 type = "HT"; 219 else if (format == RATE_MCS_HE_MSK) 220 type = "HE"; 221 else 222 type = "Unknown"; /* shouldn't happen */ 223 224 mcs = format == RATE_MCS_HT_MSK ? 225 RATE_HT_MCS_INDEX(rate) : 226 rate & RATE_MCS_CODE_MSK; 227 nss = ((rate & RATE_MCS_NSS_MSK) 228 >> RATE_MCS_NSS_POS) + 1; 229 sgi = format == RATE_MCS_HE_MSK ? 230 iwl_he_is_sgi(rate) : 231 rate & RATE_MCS_SGI_MSK; 232 233 return scnprintf(buf, bufsz, 234 "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s", 235 rate, type, iwl_rs_pretty_ant(ant), iwl_rs_pretty_bw(bw), mcs, nss, 236 (sgi) ? "SGI " : "NGI ", 237 (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", 238 (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", 239 (rate & RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "", 240 (rate & RATE_MCS_BF_MSK) ? "BF " : ""); 241 } 242 IWL_EXPORT_SYMBOL(rs_pretty_print_rate); 243 244 bool iwl_he_is_sgi(u32 rate_n_flags) 245 { 246 u32 type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; 247 u32 ltf_gi = rate_n_flags & RATE_MCS_HE_GI_LTF_MSK; 248 249 if (type == RATE_MCS_HE_TYPE_SU || 250 type == RATE_MCS_HE_TYPE_EXT_SU) 251 return ltf_gi == RATE_MCS_HE_SU_4_LTF_08_GI; 252 return false; 253 } 254 IWL_EXPORT_SYMBOL(iwl_he_is_sgi); 255 256