aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex/11ac.c
diff options
context:
space:
mode:
authorYogesh Ashok Powar <yogeshp@marvell.com>2013-02-16 00:44:30 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-02-18 15:30:39 -0500
commita5f390562a375a315292648e2da865a12b42f280 (patch)
tree4df3a0938102374e0a9208b5296ced9e7590d340 /drivers/net/wireless/mwifiex/11ac.c
parent073c9e6f86e58ba652c694b340f0460fc8156268 (diff)
mwifiex: add 802.11AC support
For STA mode, collect VHT realated IEs from the Beacons or Probe Responses and append similar VHT related IEs to association requests. For AP mode, get VHT related capability information and share it with cfg80211 at the time of wiphy register. This information is further used by cfg80211 and hostapd to start an AP with 802.11AC support. Currently only 8897 supports 802.11AC. Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com> Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Nishant Sarmukadam <nishants@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Frank Huang <frankh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwifiex/11ac.c')
-rw-r--r--drivers/net/wireless/mwifiex/11ac.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
new file mode 100644
index 000000000000..cf43b3c29250
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -0,0 +1,261 @@
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 */
29static u16
30mwifiex_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
95static void
96mwifiex_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
109static void
110mwifiex_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
166int 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 == HostCmd_BSS_MODE_IBSS) {
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}