1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * nxpwifi 802.11ac helpers
4 * Copyright 2011-2024 NXP
5 */
6
7 #include "cfg.h"
8 #include "fw.h"
9 #include "main.h"
10 #include "11ac.h"
11
12 /* Map VHT MCS/NSS to highest data rate (Mbps), long GI. */
13 static const u16 max_rate_lgi_80MHZ[8][3] = {
14 {0x124, 0x15F, 0x186}, /* NSS = 1 */
15 {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
16 {0x36D, 0x41D, 0x492}, /* NSS = 3 */
17 {0x492, 0x57C, 0x618}, /* NSS = 4 */
18 {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
19 {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
20 {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
21 {0x924, 0xAF8, 0xC30} /* NSS = 8 */
22 };
23
24 static const u16 max_rate_lgi_160MHZ[8][3] = {
25 {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
26 {0x492, 0x57C, 0x618}, /* NSS = 2 */
27 {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
28 {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
29 {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
30 {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
31 {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
32 {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
33 };
34
35 /* Convert 2-bit MCS map to highest long-GI VHT data rate. */
36 static u16
nxpwifi_convert_mcsmap_to_maxrate(struct nxpwifi_private * priv,u16 bands,u16 mcs_map)37 nxpwifi_convert_mcsmap_to_maxrate(struct nxpwifi_private *priv,
38 u16 bands, u16 mcs_map)
39 {
40 u8 i, nss, mcs;
41 u16 max_rate = 0;
42 u32 usr_vht_cap_info = 0;
43 struct nxpwifi_adapter *adapter = priv->adapter;
44
45 if (bands & BAND_AAC)
46 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
47 else
48 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
49
50 /* Find max supported NSS. */
51 nss = 1;
52 for (i = 1; i <= 8; i++) {
53 mcs = GET_VHTNSSMCS(mcs_map, i);
54 if (mcs < IEEE80211_VHT_MCS_NOT_SUPPORTED)
55 nss = i;
56 }
57 mcs = GET_VHTNSSMCS(mcs_map, nss);
58
59 /* If not supported, fall back to 0-9. */
60 if (mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED)
61 mcs = IEEE80211_VHT_MCS_SUPPORT_0_9;
62
63 if (u32_get_bits(usr_vht_cap_info, IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
64 /* Support 160 MHz. */
65 max_rate = max_rate_lgi_160MHZ[nss - 1][mcs];
66 if (!max_rate)
67 /* MCS9 not supported in NSS6. */
68 max_rate = max_rate_lgi_160MHZ[nss - 1][mcs - 1];
69 } else {
70 max_rate = max_rate_lgi_80MHZ[nss - 1][mcs];
71 if (!max_rate)
72 /* MCS9 not supported in NSS3. */
73 max_rate = max_rate_lgi_80MHZ[nss - 1][mcs - 1];
74 }
75
76 return max_rate;
77 }
78
79 static void
nxpwifi_fill_vht_cap_info(struct nxpwifi_private * priv,struct ieee80211_vht_cap * vht_cap,u16 bands)80 nxpwifi_fill_vht_cap_info(struct nxpwifi_private *priv,
81 struct ieee80211_vht_cap *vht_cap, u16 bands)
82 {
83 struct nxpwifi_adapter *adapter = priv->adapter;
84
85 if (bands & BAND_A)
86 vht_cap->vht_cap_info =
87 cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a);
88 else
89 vht_cap->vht_cap_info =
90 cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg);
91 }
92
93 void
nxpwifi_fill_vht_cap_tlv(struct nxpwifi_private * priv,struct ieee80211_vht_cap * vht_cap,u16 bands)94 nxpwifi_fill_vht_cap_tlv(struct nxpwifi_private *priv,
95 struct ieee80211_vht_cap *vht_cap, u16 bands)
96 {
97 struct nxpwifi_adapter *adapter = priv->adapter;
98 u16 mcs_map_user, mcs_map_resp, mcs_map_result;
99 u16 mcs_user, mcs_resp, nss, tmp;
100
101 /* Fill VHT capability info. */
102 nxpwifi_fill_vht_cap_info(priv, vht_cap, bands);
103
104 /* RX MCS set: min(user, AP). */
105 mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
106 mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);
107 mcs_map_result = 0;
108
109 for (nss = 1; nss <= 8; nss++) {
110 mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
111 mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
112
113 if (mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED ||
114 mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED)
115 SET_VHTNSSMCS(mcs_map_result, nss,
116 IEEE80211_VHT_MCS_NOT_SUPPORTED);
117 else
118 SET_VHTNSSMCS(mcs_map_result, nss,
119 min(mcs_user, mcs_resp));
120 }
121
122 vht_cap->supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
123
124 tmp = nxpwifi_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
125 vht_cap->supp_mcs.rx_highest = cpu_to_le16(tmp);
126
127 /* TX MCS set: min(user, AP). */
128 mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support);
129 mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map);
130 mcs_map_result = 0;
131
132 for (nss = 1; nss <= 8; nss++) {
133 mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
134 mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
135 if (mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED ||
136 mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED)
137 SET_VHTNSSMCS(mcs_map_result, nss,
138 IEEE80211_VHT_MCS_NOT_SUPPORTED);
139 else
140 SET_VHTNSSMCS(mcs_map_result, nss,
141 min(mcs_user, mcs_resp));
142 }
143
144 vht_cap->supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
145
146 tmp = nxpwifi_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
147 vht_cap->supp_mcs.tx_highest = cpu_to_le16(tmp);
148 }
149
nxpwifi_cmd_append_11ac_tlv(struct nxpwifi_private * priv,struct nxpwifi_bssdescriptor * bss_desc,u8 ** buffer)150 int nxpwifi_cmd_append_11ac_tlv(struct nxpwifi_private *priv,
151 struct nxpwifi_bssdescriptor *bss_desc,
152 u8 **buffer)
153 {
154 struct nxpwifi_ie_types_vhtcap *vht_cap;
155 struct nxpwifi_ie_types_oper_mode_ntf *oper_ntf;
156 struct ieee_types_oper_mode_ntf *ieee_oper_ntf;
157 struct nxpwifi_ie_types_vht_oper *vht_op;
158 struct nxpwifi_adapter *adapter = priv->adapter;
159 u8 supp_chwd_set;
160 u32 usr_vht_cap_info;
161 int ret_len = 0;
162
163 if (bss_desc->bss_band & BAND_A)
164 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
165 else
166 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
167
168 /* VHT Capabilities element. */
169 if (bss_desc->bcn_vht_cap) {
170 vht_cap = (struct nxpwifi_ie_types_vhtcap *)*buffer;
171 memset(vht_cap, 0, sizeof(*vht_cap));
172 vht_cap->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
173 vht_cap->header.len =
174 cpu_to_le16(sizeof(struct ieee80211_vht_cap));
175 memcpy((u8 *)vht_cap + sizeof(struct nxpwifi_ie_types_header),
176 (u8 *)bss_desc->bcn_vht_cap,
177 le16_to_cpu(vht_cap->header.len));
178
179 nxpwifi_fill_vht_cap_tlv(priv, &vht_cap->vht_cap,
180 bss_desc->bss_band);
181 *buffer += sizeof(*vht_cap);
182 ret_len += sizeof(*vht_cap);
183 }
184
185 /* VHT Operation element. */
186 if (bss_desc->bcn_vht_oper) {
187 if (priv->bss_mode == NL80211_IFTYPE_STATION) {
188 vht_op = (struct nxpwifi_ie_types_vht_oper *)*buffer;
189 memset(vht_op, 0, sizeof(*vht_op));
190 vht_op->header.type =
191 cpu_to_le16(WLAN_EID_VHT_OPERATION);
192 vht_op->header.len = cpu_to_le16(sizeof(*vht_op) -
193 sizeof(struct nxpwifi_ie_types_header));
194 memcpy((u8 *)vht_op +
195 sizeof(struct nxpwifi_ie_types_header),
196 (u8 *)bss_desc->bcn_vht_oper,
197 le16_to_cpu(vht_op->header.len));
198
199 /* Negotiate channel width; keep peer's center freq. */
200 supp_chwd_set = u32_get_bits(usr_vht_cap_info,
201 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK);
202
203 switch (supp_chwd_set) {
204 case 0:
205 vht_op->chan_width =
206 min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ,
207 bss_desc->bcn_vht_oper->chan_width);
208 break;
209 case 1:
210 vht_op->chan_width =
211 min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ,
212 bss_desc->bcn_vht_oper->chan_width);
213 break;
214 case 2:
215 vht_op->chan_width =
216 min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ,
217 bss_desc->bcn_vht_oper->chan_width);
218 break;
219 default:
220 vht_op->chan_width =
221 IEEE80211_VHT_CHANWIDTH_USE_HT;
222 break;
223 }
224
225 *buffer += sizeof(*vht_op);
226 ret_len += sizeof(*vht_op);
227 }
228 }
229
230 /* Operating Mode Notification element. */
231 if (bss_desc->oper_mode) {
232 ieee_oper_ntf = bss_desc->oper_mode;
233 oper_ntf = (void *)*buffer;
234 memset(oper_ntf, 0, sizeof(*oper_ntf));
235 oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF);
236 oper_ntf->header.len = cpu_to_le16(sizeof(u8));
237 oper_ntf->oper_mode = ieee_oper_ntf->oper_mode;
238 *buffer += sizeof(*oper_ntf);
239 ret_len += sizeof(*oper_ntf);
240 }
241
242 return ret_len;
243 }
244
nxpwifi_cmd_11ac_cfg(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,u16 cmd_action,struct nxpwifi_11ac_vht_cfg * cfg)245 int nxpwifi_cmd_11ac_cfg(struct nxpwifi_private *priv,
246 struct host_cmd_ds_command *cmd, u16 cmd_action,
247 struct nxpwifi_11ac_vht_cfg *cfg)
248 {
249 struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
250
251 cmd->command = cpu_to_le16(HOST_CMD_11AC_CFG);
252 cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
253 S_DS_GEN);
254 vhtcfg->action = cpu_to_le16(cmd_action);
255 vhtcfg->band_config = cfg->band_config;
256 vhtcfg->misc_config = cfg->misc_config;
257 vhtcfg->cap_info = cpu_to_le32(cfg->cap_info);
258 vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set);
259 vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set);
260
261 return 0;
262 }
263
264 /* Initialize BlockAck parameters for 11ac. */
nxpwifi_set_11ac_ba_params(struct nxpwifi_private * priv)265 void nxpwifi_set_11ac_ba_params(struct nxpwifi_private *priv)
266 {
267 priv->add_ba_param.timeout = NXPWIFI_DEFAULT_BLOCK_ACK_TIMEOUT;
268
269 if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) {
270 priv->add_ba_param.tx_win_size =
271 NXPWIFI_11AC_UAP_AMPDU_DEF_TXWINSIZE;
272 priv->add_ba_param.rx_win_size =
273 NXPWIFI_11AC_UAP_AMPDU_DEF_RXWINSIZE;
274 } else {
275 priv->add_ba_param.tx_win_size =
276 NXPWIFI_11AC_STA_AMPDU_DEF_TXWINSIZE;
277 priv->add_ba_param.rx_win_size =
278 NXPWIFI_11AC_STA_AMPDU_DEF_RXWINSIZE;
279 }
280 }
281