]> Pileus Git - ~andy/linux/blob - drivers/net/wireless/mwifiex/11ac.c
rbd: drop an unsafe assertion
[~andy/linux] / drivers / net / wireless / mwifiex / 11ac.c
1 /*
2  * Marvell Wireless LAN device driver: 802.11ac
3  *
4  * Copyright (C) 2013, Marvell International Ltd.
5  *
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.
13  *
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.
18  */
19
20 #include "decl.h"
21 #include "ioctl.h"
22 #include "fw.h"
23 #include "main.h"
24 #include "11ac.h"
25
26 /* This function converts the 2-bit MCS map to the highest long GI
27  * VHT data rate.
28  */
29 static u16
30 mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv,
31                                   u8 bands, u16 mcs_map)
32 {
33         u8 i, nss, max_mcs;
34         u16 max_rate = 0;
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
39          */
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 */
49         };
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 */
59         };
60
61         if (bands & BAND_AAC)
62                 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
63         else
64                 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
65
66         /* find the max NSS supported */
67         nss = 0;
68         for (i = 0; i < 8; i++) {
69                 max_mcs = (mcs_map >> (2 * i)) & 0x3;
70                 if (max_mcs < 3)
71                         nss = i;
72         }
73         max_mcs = (mcs_map >> (2 * nss)) & 0x3;
74
75         /* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9 */
76         if (max_mcs >= 3)
77                 max_mcs = 2;
78
79         if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) {
80                 /* support 160 MHz */
81                 max_rate = max_rate_lgi_160MHZ[nss][max_mcs];
82                 if (!max_rate)
83                         /* MCS9 is not supported in NSS6 */
84                         max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1];
85         } else {
86                 max_rate = max_rate_lgi_80MHZ[nss][max_mcs];
87                 if (!max_rate)
88                         /* MCS9 is not supported in NSS3 */
89                         max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1];
90         }
91
92         return max_rate;
93 }
94
95 static void
96 mwifiex_fill_vht_cap_info(struct mwifiex_private *priv,
97                           struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
98 {
99         struct mwifiex_adapter *adapter = priv->adapter;
100
101         if (bands & BAND_A)
102                 vht_cap->vht_cap.vht_cap_info =
103                                 cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a);
104         else
105                 vht_cap->vht_cap.vht_cap_info =
106                                 cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg);
107 }
108
109 static void
110 mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
111                          struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
112 {
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;
116
117         /* Fill VHT cap info */
118         mwifiex_fill_vht_cap_info(priv, vht_cap, bands);
119
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);
123         mcs_map_result = 0;
124
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);
128
129                 if ((mcs_user == NO_NSS_SUPPORT) ||
130                     (mcs_resp == NO_NSS_SUPPORT))
131                         SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
132                 else
133                         SET_VHTNSSMCS(mcs_map_result, nss,
134                                       min(mcs_user, mcs_resp));
135         }
136
137         vht_cap->vht_cap.supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
138
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);
141
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);
145         mcs_map_result = 0;
146
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);
153                 else
154                         SET_VHTNSSMCS(mcs_map_result, nss,
155                                       min(mcs_user, mcs_resp));
156         }
157
158         vht_cap->vht_cap.supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
159
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);
162
163         return;
164 }
165
166 int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
167                              struct mwifiex_bssdescriptor *bss_desc,
168                              u8 **buffer)
169 {
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;
175         u8 supp_chwd_set;
176         u32 usr_vht_cap_info;
177         int ret_len = 0;
178
179         if (bss_desc->bss_band & BAND_A)
180                 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
181         else
182                 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
183
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));
195
196                 mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
197                 *buffer += sizeof(*vht_cap);
198                 ret_len += sizeof(*vht_cap);
199         }
200
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));
215
216                         /* negotiate the channel width and central freq
217                          * and keep the central freq as the peer suggests
218                          */
219                         supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
220
221                         switch (supp_chwd_set) {
222                         case 0:
223                                 vht_op->chan_width =
224                                      min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ,
225                                            bss_desc->bcn_vht_oper->chan_width);
226                                 break;
227                         case 1:
228                                 vht_op->chan_width =
229                                      min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ,
230                                            bss_desc->bcn_vht_oper->chan_width);
231                                 break;
232                         case 2:
233                                 vht_op->chan_width =
234                                      min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ,
235                                            bss_desc->bcn_vht_oper->chan_width);
236                                 break;
237                         default:
238                                 vht_op->chan_width =
239                                      IEEE80211_VHT_CHANWIDTH_USE_HT;
240                                 break;
241                         }
242
243                         *buffer += sizeof(*vht_op);
244                         ret_len += sizeof(*vht_op);
245                 }
246         }
247
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);
258         }
259
260         return ret_len;
261 }
262
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)
266 {
267         struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
268
269         cmd->command = cpu_to_le16(HostCmd_CMD_11AC_CFG);
270         cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
271                                 S_DS_GEN);
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);
278
279         return 0;
280 }
281
282 /* This function initializes the BlockACK setup information for given
283  * mwifiex_private structure for 11ac enabled networks.
284  */
285 void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv)
286 {
287         priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
288
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;
294         } else {
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;
299         }
300
301         return;
302 }