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 u32 iwl_new_rate_from_v1(u32 rate_v1)
95 {
96 	u32 rate_v2 = 0;
97 	u32 dup = 0;
98 
99 	if (rate_v1 == 0)
100 		return rate_v1;
101 	/* convert rate */
102 	if (rate_v1 & RATE_MCS_HT_MSK_V1) {
103 		u32 nss = 0;
104 
105 		rate_v2 |= RATE_MCS_HT_MSK;
106 		rate_v2 |=
107 			rate_v1 & RATE_HT_MCS_RATE_CODE_MSK_V1;
108 		nss = (rate_v1 & RATE_HT_MCS_MIMO2_MSK) >>
109 			RATE_HT_MCS_NSS_POS_V1;
110 		rate_v2 |= nss << RATE_MCS_NSS_POS;
111 	} else if (rate_v1 & RATE_MCS_VHT_MSK_V1 ||
112 		   rate_v1 & RATE_MCS_HE_MSK_V1) {
113 		rate_v2 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK;
114 
115 		rate_v2 |= rate_v1 & RATE_VHT_MCS_MIMO2_MSK;
116 
117 		if (rate_v1 & RATE_MCS_HE_MSK_V1) {
118 			u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1;
119 			u32 he_type = he_type_bits >> RATE_MCS_HE_TYPE_POS_V1;
120 			u32 he_106t = (rate_v1 & RATE_MCS_HE_106T_MSK_V1) >>
121 				RATE_MCS_HE_106T_POS_V1;
122 			u32 he_gi_ltf = (rate_v1 & RATE_MCS_HE_GI_LTF_MSK_V1) >>
123 				RATE_MCS_HE_GI_LTF_POS;
124 
125 			if ((he_type_bits == RATE_MCS_HE_TYPE_SU ||
126 			     he_type_bits == RATE_MCS_HE_TYPE_EXT_SU) &&
127 			    he_gi_ltf == RATE_MCS_HE_SU_4_LTF)
128 				/* the new rate have an additional bit to
129 				 * represent the value 4 rather then using SGI
130 				 * bit for this purpose - as it was done in the old
131 				 * rate */
132 				he_gi_ltf += (rate_v1 & RATE_MCS_SGI_MSK_V1) >>
133 					RATE_MCS_SGI_POS_V1;
134 
135 			rate_v2 |= he_gi_ltf << RATE_MCS_HE_GI_LTF_POS;
136 			rate_v2 |= he_type << RATE_MCS_HE_TYPE_POS;
137 			rate_v2 |= he_106t << RATE_MCS_HE_106T_POS;
138 			rate_v2 |= rate_v1 & RATE_HE_DUAL_CARRIER_MODE_MSK;
139 			rate_v2 |= RATE_MCS_HE_MSK;
140 		} else {
141 			rate_v2 |= RATE_MCS_VHT_MSK;
142 		}
143 	/* if legacy format */
144 	} else {
145 		u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1);
146 
147 		WARN_ON(legacy_rate < 0);
148 		rate_v2 |= legacy_rate;
149 		if (!(rate_v1 & RATE_MCS_CCK_MSK_V1))
150 			rate_v2 |= RATE_MCS_LEGACY_OFDM_MSK;
151 	}
152 
153 	/* convert flags */
154 	if (rate_v1 & RATE_MCS_LDPC_MSK_V1)
155 		rate_v2 |= RATE_MCS_LDPC_MSK;
156 	rate_v2 |= (rate_v1 & RATE_MCS_CHAN_WIDTH_MSK_V1) |
157 		(rate_v1 & RATE_MCS_ANT_AB_MSK) |
158 		(rate_v1 & RATE_MCS_STBC_MSK) |
159 		(rate_v1 & RATE_MCS_BF_MSK);
160 
161 	dup = (rate_v1 & RATE_MCS_DUP_MSK_V1) >> RATE_MCS_DUP_POS_V1;
162 	if (dup) {
163 		rate_v2 |= RATE_MCS_DUP_MSK;
164 		rate_v2 |= dup << RATE_MCS_CHAN_WIDTH_POS;
165 	}
166 
167 	if ((!(rate_v1 & RATE_MCS_HE_MSK_V1)) &&
168 	    (rate_v1 & RATE_MCS_SGI_MSK_V1))
169 		rate_v2 |= RATE_MCS_SGI_MSK;
170 
171 	return rate_v2;
172 }
173 IWL_EXPORT_SYMBOL(iwl_new_rate_from_v1);
174 
175 u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)
176 {
177 	int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;
178 	int idx;
179 	bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1);
180 	int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0;
181 	int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;
182 
183 	for (idx = offset; idx < last; idx++)
184 		if (iwl_fw_rate_idx_to_plcp(idx) == rate)
185 			return idx - offset;
186 	return -1;
187 }
188 
189 int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)
190 {
191 	char *type;
192 	u8 mcs = 0, nss = 0;
193 	u8 ant = (rate & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS;
194 	u32 bw = (rate & RATE_MCS_CHAN_WIDTH_MSK) >>
195 		RATE_MCS_CHAN_WIDTH_POS;
196 	u32 format = rate & RATE_MCS_MOD_TYPE_MSK;
197 	bool sgi;
198 
199 	if (format == RATE_MCS_CCK_MSK ||
200 	    format == RATE_MCS_LEGACY_OFDM_MSK) {
201 		int legacy_rate = rate & RATE_LEGACY_RATE_MSK;
202 		int index = format == RATE_MCS_CCK_MSK ?
203 			legacy_rate :
204 			legacy_rate + IWL_FIRST_OFDM_RATE;
205 
206 		return scnprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps",
207 				 iwl_rs_pretty_ant(ant),
208 				 index == IWL_RATE_INVALID ? "BAD" :
209 				 iwl_rate_mcs(index)->mbps);
210 	}
211 
212 	if (format ==  RATE_MCS_VHT_MSK)
213 		type = "VHT";
214 	else if (format ==  RATE_MCS_HT_MSK)
215 		type = "HT";
216 	else if (format == RATE_MCS_HE_MSK)
217 		type = "HE";
218 	else
219 		type = "Unknown"; /* shouldn't happen */
220 
221 	mcs = format == RATE_MCS_HT_MSK ?
222 		RATE_HT_MCS_INDEX(rate) :
223 		rate & RATE_MCS_CODE_MSK;
224 	nss = ((rate & RATE_MCS_NSS_MSK)
225 	       >> RATE_MCS_NSS_POS) + 1;
226 	sgi = format == RATE_MCS_HE_MSK ?
227 		iwl_he_is_sgi(rate) :
228 		rate & RATE_MCS_SGI_MSK;
229 
230 	return scnprintf(buf, bufsz,
231 			 "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s",
232 			 rate, type, iwl_rs_pretty_ant(ant), iwl_rs_pretty_bw(bw), mcs, nss,
233 			 (sgi) ? "SGI " : "NGI ",
234 			 (rate & RATE_MCS_STBC_MSK) ? "STBC " : "",
235 			 (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "",
236 			 (rate & RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "",
237 			 (rate & RATE_MCS_BF_MSK) ? "BF " : "");
238 }
239 IWL_EXPORT_SYMBOL(rs_pretty_print_rate);
240 
241 bool iwl_he_is_sgi(u32 rate_n_flags)
242 {
243 	u32 type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
244 	u32 ltf_gi = rate_n_flags & RATE_MCS_HE_GI_LTF_MSK;
245 
246 	if (type == RATE_MCS_HE_TYPE_SU ||
247 	    type == RATE_MCS_HE_TYPE_EXT_SU)
248 		return ltf_gi == RATE_MCS_HE_SU_4_LTF_08_GI;
249 	return false;
250 }
251 IWL_EXPORT_SYMBOL(iwl_he_is_sgi);
252 
253