2 * Marvell Wireless LAN device driver: 802.11ac
4 * Copyright (C) 2013, Marvell International Ltd.
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
26 /* This function converts the 2-bit MCS map to the highest long GI
30 mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private
*priv
,
31 u8 bands
, u16 mcs_map
)
35 u32 usr_vht_cap_info
= 0;
36 struct mwifiex_adapter
*adapter
= priv
->adapter
;
37 /* tables of the MCS map to the highest data rate (in Mbps)
38 * supported for long GI
40 u16 max_rate_lgi_80MHZ
[8][3] = {
41 {0x124, 0x15F, 0x186}, /* NSS = 1 */
42 {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
43 {0x36D, 0x41D, 0x492}, /* NSS = 3 */
44 {0x492, 0x57C, 0x618}, /* NSS = 4 */
45 {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
46 {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
47 {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
48 {0x924, 0xAF8, 0xC30} /* NSS = 8 */
50 u16 max_rate_lgi_160MHZ
[8][3] = {
51 {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
52 {0x492, 0x57C, 0x618}, /* NSS = 2 */
53 {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
54 {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
55 {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
56 {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
57 {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
58 {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
62 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_a
;
64 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_bg
;
66 /* find the max NSS supported */
68 for (i
= 0; i
< 8; i
++) {
69 max_mcs
= (mcs_map
>> (2 * i
)) & 0x3;
73 max_mcs
= (mcs_map
>> (2 * nss
)) & 0x3;
75 /* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9 */
79 if (GET_VHTCAP_CHWDSET(usr_vht_cap_info
)) {
81 max_rate
= max_rate_lgi_160MHZ
[nss
][max_mcs
];
83 /* MCS9 is not supported in NSS6 */
84 max_rate
= max_rate_lgi_160MHZ
[nss
][max_mcs
- 1];
86 max_rate
= max_rate_lgi_80MHZ
[nss
][max_mcs
];
88 /* MCS9 is not supported in NSS3 */
89 max_rate
= max_rate_lgi_80MHZ
[nss
][max_mcs
- 1];
96 mwifiex_fill_vht_cap_info(struct mwifiex_private
*priv
,
97 struct mwifiex_ie_types_vhtcap
*vht_cap
, u8 bands
)
99 struct mwifiex_adapter
*adapter
= priv
->adapter
;
102 vht_cap
->vht_cap
.vht_cap_info
=
103 cpu_to_le32(adapter
->usr_dot_11ac_dev_cap_a
);
105 vht_cap
->vht_cap
.vht_cap_info
=
106 cpu_to_le32(adapter
->usr_dot_11ac_dev_cap_bg
);
110 mwifiex_fill_vht_cap_tlv(struct mwifiex_private
*priv
,
111 struct mwifiex_ie_types_vhtcap
*vht_cap
, u8 bands
)
113 struct mwifiex_adapter
*adapter
= priv
->adapter
;
114 u16 mcs_map_user
, mcs_map_resp
, mcs_map_result
;
115 u16 mcs_user
, mcs_resp
, nss
, tmp
;
117 /* Fill VHT cap info */
118 mwifiex_fill_vht_cap_info(priv
, vht_cap
, bands
);
120 /* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */
121 mcs_map_user
= GET_DEVRXMCSMAP(adapter
->usr_dot_11ac_mcs_support
);
122 mcs_map_resp
= le16_to_cpu(vht_cap
->vht_cap
.supp_mcs
.rx_mcs_map
);
125 for (nss
= 1; nss
<= 8; nss
++) {
126 mcs_user
= GET_VHTNSSMCS(mcs_map_user
, nss
);
127 mcs_resp
= GET_VHTNSSMCS(mcs_map_resp
, nss
);
129 if ((mcs_user
== NO_NSS_SUPPORT
) ||
130 (mcs_resp
== NO_NSS_SUPPORT
))
131 SET_VHTNSSMCS(mcs_map_result
, nss
, NO_NSS_SUPPORT
);
133 SET_VHTNSSMCS(mcs_map_result
, nss
,
134 min(mcs_user
, mcs_resp
));
137 vht_cap
->vht_cap
.supp_mcs
.rx_mcs_map
= cpu_to_le16(mcs_map_result
);
139 tmp
= mwifiex_convert_mcsmap_to_maxrate(priv
, bands
, mcs_map_result
);
140 vht_cap
->vht_cap
.supp_mcs
.rx_highest
= cpu_to_le16(tmp
);
142 /* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */
143 mcs_map_user
= GET_DEVTXMCSMAP(adapter
->usr_dot_11ac_mcs_support
);
144 mcs_map_resp
= le16_to_cpu(vht_cap
->vht_cap
.supp_mcs
.tx_mcs_map
);
147 for (nss
= 1; nss
<= 8; nss
++) {
148 mcs_user
= GET_VHTNSSMCS(mcs_map_user
, nss
);
149 mcs_resp
= GET_VHTNSSMCS(mcs_map_resp
, nss
);
150 if ((mcs_user
== NO_NSS_SUPPORT
) ||
151 (mcs_resp
== NO_NSS_SUPPORT
))
152 SET_VHTNSSMCS(mcs_map_result
, nss
, NO_NSS_SUPPORT
);
154 SET_VHTNSSMCS(mcs_map_result
, nss
,
155 min(mcs_user
, mcs_resp
));
158 vht_cap
->vht_cap
.supp_mcs
.tx_mcs_map
= cpu_to_le16(mcs_map_result
);
160 tmp
= mwifiex_convert_mcsmap_to_maxrate(priv
, bands
, mcs_map_result
);
161 vht_cap
->vht_cap
.supp_mcs
.tx_highest
= cpu_to_le16(tmp
);
166 int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private
*priv
,
167 struct mwifiex_bssdescriptor
*bss_desc
,
170 struct mwifiex_ie_types_vhtcap
*vht_cap
;
171 struct mwifiex_ie_types_oper_mode_ntf
*oper_ntf
;
172 struct ieee_types_oper_mode_ntf
*ieee_oper_ntf
;
173 struct mwifiex_ie_types_vht_oper
*vht_op
;
174 struct mwifiex_adapter
*adapter
= priv
->adapter
;
176 u32 usr_vht_cap_info
;
179 if (bss_desc
->bss_band
& BAND_A
)
180 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_a
;
182 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_bg
;
184 /* VHT Capabilities IE */
185 if (bss_desc
->bcn_vht_cap
) {
186 vht_cap
= (struct mwifiex_ie_types_vhtcap
*)*buffer
;
187 memset(vht_cap
, 0, sizeof(*vht_cap
));
188 vht_cap
->header
.type
= cpu_to_le16(WLAN_EID_VHT_CAPABILITY
);
189 vht_cap
->header
.len
=
190 cpu_to_le16(sizeof(struct ieee80211_vht_cap
));
191 memcpy((u8
*)vht_cap
+ sizeof(struct mwifiex_ie_types_header
),
192 (u8
*)bss_desc
->bcn_vht_cap
+
193 sizeof(struct ieee_types_header
),
194 le16_to_cpu(vht_cap
->header
.len
));
196 mwifiex_fill_vht_cap_tlv(priv
, vht_cap
, bss_desc
->bss_band
);
197 *buffer
+= sizeof(*vht_cap
);
198 ret_len
+= sizeof(*vht_cap
);
201 /* VHT Operation IE */
202 if (bss_desc
->bcn_vht_oper
) {
203 if (priv
->bss_mode
== NL80211_IFTYPE_STATION
) {
204 vht_op
= (struct mwifiex_ie_types_vht_oper
*)*buffer
;
205 memset(vht_op
, 0, sizeof(*vht_op
));
206 vht_op
->header
.type
=
207 cpu_to_le16(WLAN_EID_VHT_OPERATION
);
208 vht_op
->header
.len
= cpu_to_le16(sizeof(*vht_op
) -
209 sizeof(struct mwifiex_ie_types_header
));
210 memcpy((u8
*)vht_op
+
211 sizeof(struct mwifiex_ie_types_header
),
212 (u8
*)bss_desc
->bcn_vht_oper
+
213 sizeof(struct ieee_types_header
),
214 le16_to_cpu(vht_op
->header
.len
));
216 /* negotiate the channel width and central freq
217 * and keep the central freq as the peer suggests
219 supp_chwd_set
= GET_VHTCAP_CHWDSET(usr_vht_cap_info
);
221 switch (supp_chwd_set
) {
224 min_t(u8
, IEEE80211_VHT_CHANWIDTH_80MHZ
,
225 bss_desc
->bcn_vht_oper
->chan_width
);
229 min_t(u8
, IEEE80211_VHT_CHANWIDTH_160MHZ
,
230 bss_desc
->bcn_vht_oper
->chan_width
);
234 min_t(u8
, IEEE80211_VHT_CHANWIDTH_80P80MHZ
,
235 bss_desc
->bcn_vht_oper
->chan_width
);
239 IEEE80211_VHT_CHANWIDTH_USE_HT
;
243 *buffer
+= sizeof(*vht_op
);
244 ret_len
+= sizeof(*vht_op
);
248 /* Operating Mode Notification IE */
249 if (bss_desc
->oper_mode
) {
250 ieee_oper_ntf
= bss_desc
->oper_mode
;
251 oper_ntf
= (void *)*buffer
;
252 memset(oper_ntf
, 0, sizeof(*oper_ntf
));
253 oper_ntf
->header
.type
= cpu_to_le16(WLAN_EID_OPMODE_NOTIF
);
254 oper_ntf
->header
.len
= cpu_to_le16(sizeof(u8
));
255 oper_ntf
->oper_mode
= ieee_oper_ntf
->oper_mode
;
256 *buffer
+= sizeof(*oper_ntf
);
257 ret_len
+= sizeof(*oper_ntf
);
263 int mwifiex_cmd_11ac_cfg(struct mwifiex_private
*priv
,
264 struct host_cmd_ds_command
*cmd
, u16 cmd_action
,
265 struct mwifiex_11ac_vht_cfg
*cfg
)
267 struct host_cmd_11ac_vht_cfg
*vhtcfg
= &cmd
->params
.vht_cfg
;
269 cmd
->command
= cpu_to_le16(HostCmd_CMD_11AC_CFG
);
270 cmd
->size
= cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg
) +
272 vhtcfg
->action
= cpu_to_le16(cmd_action
);
273 vhtcfg
->band_config
= cfg
->band_config
;
274 vhtcfg
->misc_config
= cfg
->misc_config
;
275 vhtcfg
->cap_info
= cpu_to_le32(cfg
->cap_info
);
276 vhtcfg
->mcs_tx_set
= cpu_to_le32(cfg
->mcs_tx_set
);
277 vhtcfg
->mcs_rx_set
= cpu_to_le32(cfg
->mcs_rx_set
);
282 /* This function initializes the BlockACK setup information for given
283 * mwifiex_private structure for 11ac enabled networks.
285 void mwifiex_set_11ac_ba_params(struct mwifiex_private
*priv
)
287 priv
->add_ba_param
.timeout
= MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT
;
289 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_UAP
) {
290 priv
->add_ba_param
.tx_win_size
=
291 MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE
;
292 priv
->add_ba_param
.rx_win_size
=
293 MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE
;
295 priv
->add_ba_param
.tx_win_size
=
296 MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE
;
297 priv
->add_ba_param
.rx_win_size
=
298 MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE
;