]> Pileus Git - ~andy/linux/blob - drivers/net/wireless/mwifiex/11ac.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
[~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                        le16_to_cpu(vht_cap->header.len));
194
195                 mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
196                 *buffer += sizeof(*vht_cap);
197                 ret_len += sizeof(*vht_cap);
198         }
199
200         /* VHT Operation IE */
201         if (bss_desc->bcn_vht_oper) {
202                 if (priv->bss_mode == NL80211_IFTYPE_STATION) {
203                         vht_op = (struct mwifiex_ie_types_vht_oper *)*buffer;
204                         memset(vht_op, 0, sizeof(*vht_op));
205                         vht_op->header.type =
206                                         cpu_to_le16(WLAN_EID_VHT_OPERATION);
207                         vht_op->header.len  = cpu_to_le16(sizeof(*vht_op) -
208                                       sizeof(struct mwifiex_ie_types_header));
209                         memcpy((u8 *)vht_op +
210                                 sizeof(struct mwifiex_ie_types_header),
211                                (u8 *)bss_desc->bcn_vht_oper +
212                                sizeof(struct ieee_types_header),
213                                le16_to_cpu(vht_op->header.len));
214
215                         /* negotiate the channel width and central freq
216                          * and keep the central freq as the peer suggests
217                          */
218                         supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
219
220                         switch (supp_chwd_set) {
221                         case 0:
222                                 vht_op->chan_width =
223                                      min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ,
224                                            bss_desc->bcn_vht_oper->chan_width);
225                                 break;
226                         case 1:
227                                 vht_op->chan_width =
228                                      min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ,
229                                            bss_desc->bcn_vht_oper->chan_width);
230                                 break;
231                         case 2:
232                                 vht_op->chan_width =
233                                      min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ,
234                                            bss_desc->bcn_vht_oper->chan_width);
235                                 break;
236                         default:
237                                 vht_op->chan_width =
238                                      IEEE80211_VHT_CHANWIDTH_USE_HT;
239                                 break;
240                         }
241
242                         *buffer += sizeof(*vht_op);
243                         ret_len += sizeof(*vht_op);
244                 }
245         }
246
247         /* Operating Mode Notification IE */
248         if (bss_desc->oper_mode) {
249                 ieee_oper_ntf = bss_desc->oper_mode;
250                 oper_ntf = (void *)*buffer;
251                 memset(oper_ntf, 0, sizeof(*oper_ntf));
252                 oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF);
253                 oper_ntf->header.len = cpu_to_le16(sizeof(u8));
254                 oper_ntf->oper_mode = ieee_oper_ntf->oper_mode;
255                 *buffer += sizeof(*oper_ntf);
256                 ret_len += sizeof(*oper_ntf);
257         }
258
259         return ret_len;
260 }
261
262 int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
263                          struct host_cmd_ds_command *cmd, u16 cmd_action,
264                          struct mwifiex_11ac_vht_cfg *cfg)
265 {
266         struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
267
268         cmd->command = cpu_to_le16(HostCmd_CMD_11AC_CFG);
269         cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
270                                 S_DS_GEN);
271         vhtcfg->action = cpu_to_le16(cmd_action);
272         vhtcfg->band_config = cfg->band_config;
273         vhtcfg->misc_config = cfg->misc_config;
274         vhtcfg->cap_info = cpu_to_le32(cfg->cap_info);
275         vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set);
276         vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set);
277
278         return 0;
279 }
280
281 /* This function initializes the BlockACK setup information for given
282  * mwifiex_private structure for 11ac enabled networks.
283  */
284 void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv)
285 {
286         priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
287
288         if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
289                 priv->add_ba_param.tx_win_size =
290                                            MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE;
291                 priv->add_ba_param.rx_win_size =
292                                            MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE;
293         } else {
294                 priv->add_ba_param.tx_win_size =
295                                            MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE;
296                 priv->add_ba_param.rx_win_size =
297                                            MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
298         }
299
300         return;
301 }