2 * Marvell Wireless LAN device driver: 802.11ac
4 * Copyright (C) 2013-2014, 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 /* Tables of the MCS map to the highest data rate (in Mbps) supported
29 static const u16 max_rate_lgi_80MHZ
[8][3] = {
30 {0x124, 0x15F, 0x186}, /* NSS = 1 */
31 {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
32 {0x36D, 0x41D, 0x492}, /* NSS = 3 */
33 {0x492, 0x57C, 0x618}, /* NSS = 4 */
34 {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
35 {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
36 {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
37 {0x924, 0xAF8, 0xC30} /* NSS = 8 */
40 static const u16 max_rate_lgi_160MHZ
[8][3] = {
41 {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
42 {0x492, 0x57C, 0x618}, /* NSS = 2 */
43 {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
44 {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
45 {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
46 {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
47 {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
48 {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
51 /* This function converts the 2-bit MCS map to the highest long GI
55 mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private
*priv
,
56 u8 bands
, u16 mcs_map
)
60 u32 usr_vht_cap_info
= 0;
61 struct mwifiex_adapter
*adapter
= priv
->adapter
;
64 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_a
;
66 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_bg
;
68 /* find the max NSS supported */
70 for (i
= 1; i
<= 8; i
++) {
71 mcs
= GET_VHTNSSMCS(mcs_map
, i
);
72 if (mcs
< IEEE80211_VHT_MCS_NOT_SUPPORTED
)
75 mcs
= GET_VHTNSSMCS(mcs_map
, nss
);
77 /* if mcs is 3, nss must be 1 (NSS = 1). Default mcs to MCS 0~9 */
78 if (mcs
== IEEE80211_VHT_MCS_NOT_SUPPORTED
)
79 mcs
= IEEE80211_VHT_MCS_SUPPORT_0_9
;
81 if (GET_VHTCAP_CHWDSET(usr_vht_cap_info
)) {
83 max_rate
= max_rate_lgi_160MHZ
[nss
- 1][mcs
];
85 /* MCS9 is not supported in NSS6 */
86 max_rate
= max_rate_lgi_160MHZ
[nss
- 1][mcs
- 1];
88 max_rate
= max_rate_lgi_80MHZ
[nss
- 1][mcs
];
90 /* MCS9 is not supported in NSS3 */
91 max_rate
= max_rate_lgi_80MHZ
[nss
- 1][mcs
- 1];
98 mwifiex_fill_vht_cap_info(struct mwifiex_private
*priv
,
99 struct ieee80211_vht_cap
*vht_cap
, u8 bands
)
101 struct mwifiex_adapter
*adapter
= priv
->adapter
;
104 vht_cap
->vht_cap_info
=
105 cpu_to_le32(adapter
->usr_dot_11ac_dev_cap_a
);
107 vht_cap
->vht_cap_info
=
108 cpu_to_le32(adapter
->usr_dot_11ac_dev_cap_bg
);
111 void mwifiex_fill_vht_cap_tlv(struct mwifiex_private
*priv
,
112 struct ieee80211_vht_cap
*vht_cap
, u8 bands
)
114 struct mwifiex_adapter
*adapter
= priv
->adapter
;
115 u16 mcs_map_user
, mcs_map_resp
, mcs_map_result
;
116 u16 mcs_user
, mcs_resp
, nss
, tmp
;
118 /* Fill VHT cap info */
119 mwifiex_fill_vht_cap_info(priv
, vht_cap
, bands
);
121 /* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */
122 mcs_map_user
= GET_DEVRXMCSMAP(adapter
->usr_dot_11ac_mcs_support
);
123 mcs_map_resp
= le16_to_cpu(vht_cap
->supp_mcs
.rx_mcs_map
);
126 for (nss
= 1; nss
<= 8; nss
++) {
127 mcs_user
= GET_VHTNSSMCS(mcs_map_user
, nss
);
128 mcs_resp
= GET_VHTNSSMCS(mcs_map_resp
, nss
);
130 if ((mcs_user
== IEEE80211_VHT_MCS_NOT_SUPPORTED
) ||
131 (mcs_resp
== IEEE80211_VHT_MCS_NOT_SUPPORTED
))
132 SET_VHTNSSMCS(mcs_map_result
, nss
,
133 IEEE80211_VHT_MCS_NOT_SUPPORTED
);
135 SET_VHTNSSMCS(mcs_map_result
, nss
,
136 min(mcs_user
, mcs_resp
));
139 vht_cap
->supp_mcs
.rx_mcs_map
= cpu_to_le16(mcs_map_result
);
141 tmp
= mwifiex_convert_mcsmap_to_maxrate(priv
, bands
, mcs_map_result
);
142 vht_cap
->supp_mcs
.rx_highest
= cpu_to_le16(tmp
);
144 /* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */
145 mcs_map_user
= GET_DEVTXMCSMAP(adapter
->usr_dot_11ac_mcs_support
);
146 mcs_map_resp
= le16_to_cpu(vht_cap
->supp_mcs
.tx_mcs_map
);
149 for (nss
= 1; nss
<= 8; nss
++) {
150 mcs_user
= GET_VHTNSSMCS(mcs_map_user
, nss
);
151 mcs_resp
= GET_VHTNSSMCS(mcs_map_resp
, nss
);
152 if ((mcs_user
== IEEE80211_VHT_MCS_NOT_SUPPORTED
) ||
153 (mcs_resp
== IEEE80211_VHT_MCS_NOT_SUPPORTED
))
154 SET_VHTNSSMCS(mcs_map_result
, nss
,
155 IEEE80211_VHT_MCS_NOT_SUPPORTED
);
157 SET_VHTNSSMCS(mcs_map_result
, nss
,
158 min(mcs_user
, mcs_resp
));
161 vht_cap
->supp_mcs
.tx_mcs_map
= cpu_to_le16(mcs_map_result
);
163 tmp
= mwifiex_convert_mcsmap_to_maxrate(priv
, bands
, mcs_map_result
);
164 vht_cap
->supp_mcs
.tx_highest
= cpu_to_le16(tmp
);
169 int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private
*priv
,
170 struct mwifiex_bssdescriptor
*bss_desc
,
173 struct mwifiex_ie_types_vhtcap
*vht_cap
;
174 struct mwifiex_ie_types_oper_mode_ntf
*oper_ntf
;
175 struct ieee_types_oper_mode_ntf
*ieee_oper_ntf
;
176 struct mwifiex_ie_types_vht_oper
*vht_op
;
177 struct mwifiex_adapter
*adapter
= priv
->adapter
;
179 u32 usr_vht_cap_info
;
182 if (bss_desc
->bss_band
& BAND_A
)
183 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_a
;
185 usr_vht_cap_info
= adapter
->usr_dot_11ac_dev_cap_bg
;
187 /* VHT Capabilities IE */
188 if (bss_desc
->bcn_vht_cap
) {
189 vht_cap
= (struct mwifiex_ie_types_vhtcap
*)*buffer
;
190 memset(vht_cap
, 0, sizeof(*vht_cap
));
191 vht_cap
->header
.type
= cpu_to_le16(WLAN_EID_VHT_CAPABILITY
);
192 vht_cap
->header
.len
=
193 cpu_to_le16(sizeof(struct ieee80211_vht_cap
));
194 memcpy((u8
*)vht_cap
+ sizeof(struct mwifiex_ie_types_header
),
195 (u8
*)bss_desc
->bcn_vht_cap
,
196 le16_to_cpu(vht_cap
->header
.len
));
198 mwifiex_fill_vht_cap_tlv(priv
, &vht_cap
->vht_cap
,
200 *buffer
+= sizeof(*vht_cap
);
201 ret_len
+= sizeof(*vht_cap
);
204 /* VHT Operation IE */
205 if (bss_desc
->bcn_vht_oper
) {
206 if (priv
->bss_mode
== NL80211_IFTYPE_STATION
) {
207 vht_op
= (struct mwifiex_ie_types_vht_oper
*)*buffer
;
208 memset(vht_op
, 0, sizeof(*vht_op
));
209 vht_op
->header
.type
=
210 cpu_to_le16(WLAN_EID_VHT_OPERATION
);
211 vht_op
->header
.len
= cpu_to_le16(sizeof(*vht_op
) -
212 sizeof(struct mwifiex_ie_types_header
));
213 memcpy((u8
*)vht_op
+
214 sizeof(struct mwifiex_ie_types_header
),
215 (u8
*)bss_desc
->bcn_vht_oper
,
216 le16_to_cpu(vht_op
->header
.len
));
218 /* negotiate the channel width and central freq
219 * and keep the central freq as the peer suggests
221 supp_chwd_set
= GET_VHTCAP_CHWDSET(usr_vht_cap_info
);
223 switch (supp_chwd_set
) {
226 min_t(u8
, IEEE80211_VHT_CHANWIDTH_80MHZ
,
227 bss_desc
->bcn_vht_oper
->chan_width
);
231 min_t(u8
, IEEE80211_VHT_CHANWIDTH_160MHZ
,
232 bss_desc
->bcn_vht_oper
->chan_width
);
236 min_t(u8
, IEEE80211_VHT_CHANWIDTH_80P80MHZ
,
237 bss_desc
->bcn_vht_oper
->chan_width
);
241 IEEE80211_VHT_CHANWIDTH_USE_HT
;
245 *buffer
+= sizeof(*vht_op
);
246 ret_len
+= sizeof(*vht_op
);
250 /* Operating Mode Notification IE */
251 if (bss_desc
->oper_mode
) {
252 ieee_oper_ntf
= bss_desc
->oper_mode
;
253 oper_ntf
= (void *)*buffer
;
254 memset(oper_ntf
, 0, sizeof(*oper_ntf
));
255 oper_ntf
->header
.type
= cpu_to_le16(WLAN_EID_OPMODE_NOTIF
);
256 oper_ntf
->header
.len
= cpu_to_le16(sizeof(u8
));
257 oper_ntf
->oper_mode
= ieee_oper_ntf
->oper_mode
;
258 *buffer
+= sizeof(*oper_ntf
);
259 ret_len
+= sizeof(*oper_ntf
);
265 int mwifiex_cmd_11ac_cfg(struct mwifiex_private
*priv
,
266 struct host_cmd_ds_command
*cmd
, u16 cmd_action
,
267 struct mwifiex_11ac_vht_cfg
*cfg
)
269 struct host_cmd_11ac_vht_cfg
*vhtcfg
= &cmd
->params
.vht_cfg
;
271 cmd
->command
= cpu_to_le16(HostCmd_CMD_11AC_CFG
);
272 cmd
->size
= cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg
) +
274 vhtcfg
->action
= cpu_to_le16(cmd_action
);
275 vhtcfg
->band_config
= cfg
->band_config
;
276 vhtcfg
->misc_config
= cfg
->misc_config
;
277 vhtcfg
->cap_info
= cpu_to_le32(cfg
->cap_info
);
278 vhtcfg
->mcs_tx_set
= cpu_to_le32(cfg
->mcs_tx_set
);
279 vhtcfg
->mcs_rx_set
= cpu_to_le32(cfg
->mcs_rx_set
);
284 /* This function initializes the BlockACK setup information for given
285 * mwifiex_private structure for 11ac enabled networks.
287 void mwifiex_set_11ac_ba_params(struct mwifiex_private
*priv
)
289 priv
->add_ba_param
.timeout
= MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT
;
291 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_UAP
) {
292 priv
->add_ba_param
.tx_win_size
=
293 MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE
;
294 priv
->add_ba_param
.rx_win_size
=
295 MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE
;
297 priv
->add_ba_param
.tx_win_size
=
298 MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE
;
299 priv
->add_ba_param
.rx_win_size
=
300 MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE
;
306 bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private
*priv
)
308 struct mwifiex_bssdescriptor
*bss_desc
;
309 struct ieee80211_vht_operation
*vht_oper
;
311 bss_desc
= &priv
->curr_bss_params
.bss_descriptor
;
312 vht_oper
= bss_desc
->bcn_vht_oper
;
314 if (!bss_desc
->bcn_vht_cap
|| !vht_oper
)
317 if (vht_oper
->chan_width
== IEEE80211_VHT_CHANWIDTH_USE_HT
)
323 u8
mwifiex_get_center_freq_index(struct mwifiex_private
*priv
, u8 band
,
324 u32 pri_chan
, u8 chan_bw
)
326 u8 center_freq_idx
= 0;
328 if (band
& BAND_AAC
) {
334 if (chan_bw
== IEEE80211_VHT_CHANWIDTH_80MHZ
)
335 center_freq_idx
= 42;
341 if (chan_bw
== IEEE80211_VHT_CHANWIDTH_80MHZ
)
342 center_freq_idx
= 58;
343 else if (chan_bw
== IEEE80211_VHT_CHANWIDTH_160MHZ
)
344 center_freq_idx
= 50;
350 if (chan_bw
== IEEE80211_VHT_CHANWIDTH_80MHZ
)
351 center_freq_idx
= 106;
357 if (chan_bw
== IEEE80211_VHT_CHANWIDTH_80MHZ
)
358 center_freq_idx
= 122;
359 else if (chan_bw
== IEEE80211_VHT_CHANWIDTH_160MHZ
)
360 center_freq_idx
= 114;
366 if (chan_bw
== IEEE80211_VHT_CHANWIDTH_80MHZ
)
367 center_freq_idx
= 138;
373 if (chan_bw
== IEEE80211_VHT_CHANWIDTH_80MHZ
)
374 center_freq_idx
= 155;
377 center_freq_idx
= 42;
381 return center_freq_idx
;