1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2021-2022 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
iwl_fw_rate_idx_to_plcp(int idx)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
iwl_rate_mcs(int idx)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
iwl_rs_pretty_ant(u8 ant)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
iwl_rs_pretty_bw(int bw)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
iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)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
iwl_new_rate_from_v1(u32 rate_v1)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_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 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
rs_pretty_print_rate(char * buf,int bufsz,const u32 rate)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 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 else
223 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 }
243 IWL_EXPORT_SYMBOL(rs_pretty_print_rate);
244
iwl_he_is_sgi(u32 rate_n_flags)245 bool 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 }
255 IWL_EXPORT_SYMBOL(iwl_he_is_sgi);
256
257