1 /** @file mlan_11ac.c
2 *
3 * @brief This file defines the private and adapter data
4 * structures and declares global function prototypes used
5 * in MLAN module.
6 *
7 * Copyright 2008-2024 NXP
8 *
9 * SPDX-License-Identifier: BSD-3-Clause
10 *
11 */
12
13 #include <mlan_api.h>
14
15 /* Additional WMSDK header files */
16 #include <wmerrno.h>
17 #include <osa.h>
18
19 /* Always keep this include at the end of all include files */
20 #include <mlan_remap_mem_operations.h>
21
22 /********************************************************
23 Local Variables
24 ********************************************************/
25
26 /********************************************************
27 Global Variables
28 ********************************************************/
29
30 /********************************************************
31 Local Functions
32 ********************************************************/
33 #if CONFIG_11AC
34 /**
35 * @brief determine the center frquency center index for bandwidth
36 * of 80 MHz and 160 MHz
37 *
38 * @param pmpriv A pointer to mlan_private structure
39 * @param band band
40 * @param pri_chan primary channel
41 * @param chan_bw channel bandwidth
42 *
43 * @return channel center frequency center, if found; O, otherwise
44 */
45
wlan_get_center_freq_idx(IN mlan_private * pmpriv,IN t_u8 band,IN t_u32 pri_chan,IN t_u8 chan_bw)46 t_u8 wlan_get_center_freq_idx(IN mlan_private *pmpriv, IN t_u8 band, IN t_u32 pri_chan, IN t_u8 chan_bw)
47 {
48 t_u8 center_freq_idx = 0;
49
50 if ((band & BAND_AAC) != 0U)
51 {
52 switch (pri_chan)
53 {
54 case 36:
55 case 40:
56 case 44:
57 case 48:
58 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
59 {
60 center_freq_idx = 42;
61 }
62 break;
63 case 52:
64 case 56:
65 case 60:
66 case 64:
67 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
68 {
69 center_freq_idx = 58;
70 }
71 else if (chan_bw == (t_u8)CHANNEL_BW_160MHZ)
72 {
73 center_freq_idx = 50;
74 }
75 else
76 {
77 /* Do nothing */
78 }
79 break;
80 case 100:
81 case 104:
82 case 108:
83 case 112:
84 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
85 {
86 center_freq_idx = 106;
87 }
88 break;
89 case 116:
90 case 120:
91 case 124:
92 case 128:
93 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
94 {
95 center_freq_idx = 122;
96 }
97 else if (chan_bw == (t_u8)CHANNEL_BW_160MHZ)
98 {
99 center_freq_idx = 114;
100 }
101 else
102 {
103 /* Do nothing */
104 }
105 break;
106 case 132:
107 case 136:
108 case 140:
109 case 144:
110 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
111 {
112 center_freq_idx = 138;
113 }
114 break;
115 case 149:
116 case 153:
117 case 157:
118 case 161:
119 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
120 {
121 center_freq_idx = 155;
122 }
123 break;
124 case 165:
125 case 169:
126 case 173:
127 case 177:
128 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
129 {
130 center_freq_idx = 171;
131 }
132 break;
133 case 184:
134 case 188:
135 case 192:
136 case 196:
137 if (chan_bw == (t_u8)CHANNEL_BW_80MHZ)
138 {
139 center_freq_idx = 190;
140 }
141 break;
142 default: /* error. go to the default */
143 center_freq_idx = 42;
144 break;
145 }
146 }
147 return center_freq_idx;
148 }
149 #endif
150
151 /**
152 * @brief This function gets the bitmap of nss which supports VHT mcs
153 *
154 * @param mcs_map_set VHT mcs map
155 *
156 * @return The bitmap of supported nss
157 */
wlan_get_nss_vht_mcs(t_u16 mcs_map_set)158 static t_u8 wlan_get_nss_vht_mcs(t_u16 mcs_map_set)
159 {
160 t_u8 nss, nss_map = 0;
161 for (nss = 1; nss <= 8U; nss++)
162 {
163 if (GET_VHTNSSMCS(mcs_map_set, nss) != NO_NSS_SUPPORT)
164 {
165 nss_map |= 1U << (nss - 1U);
166 }
167 }
168 PRINTM(MCMND, "Supported nss bit map:0x%02x\n", nss_map);
169 return nss_map;
170 }
171
172 /**
173 * @brief This function gets the number of nss which supports VHT mcs
174 *
175 * @param mcs_map_set VHT mcs map
176 *
177 * @return Number of supported nss
178 */
wlan_get_nss_num_vht_mcs(t_u16 mcs_map_set)179 static t_u8 wlan_get_nss_num_vht_mcs(t_u16 mcs_map_set)
180 {
181 t_u8 nss, nss_num = 0;
182 for (nss = 1; nss <= 8U; nss++)
183 {
184 if (GET_VHTNSSMCS(mcs_map_set, nss) != NO_NSS_SUPPORT)
185 {
186 nss_num++;
187 }
188 }
189 PRINTM(MCMND, "Supported nss:%d\n", nss_num);
190 return nss_num;
191 }
192
193 /**
194 * @brief This function fills the cap info
195 *
196 * @param priv A pointer to mlan_private structure
197 * @param pht_cap A pointer to MrvlIETypes_HTCap_t structure
198 * @param bands Band configuration
199 *
200 * @return N/A
201 */
wlan_fill_cap_info(mlan_private * priv,VHT_capa_t * vht_cap,t_u16 bands)202 static void wlan_fill_cap_info(mlan_private *priv, VHT_capa_t *vht_cap, t_u16 bands)
203 {
204 mlan_adapter *pmadapter = priv->adapter;
205 t_u32 usr_dot_11ac_dev_cap;
206
207 ENTER();
208
209 #if CONFIG_5GHz_SUPPORT
210 if ((bands & BAND_A) != 0U)
211 {
212 usr_dot_11ac_dev_cap = pmadapter->usr_dot_11ac_dev_cap_a;
213 }
214 else
215 #endif
216 {
217 usr_dot_11ac_dev_cap = pmadapter->usr_dot_11ac_dev_cap_bg;
218 }
219
220 vht_cap->vht_cap_info = usr_dot_11ac_dev_cap;
221 #ifdef RW610
222 if (GET_VHTCAP_MAXMPDULEN(vht_cap->vht_cap_info) != 0U)
223 RESET_11ACMAXMPDULEN(vht_cap->vht_cap_info);
224 #endif
225
226 LEAVE();
227 }
228
229 #if CONFIG_11AC
230 /**
231 * @brief Set/get 11ac configuration
232 *
233 * @param pmadapter A pointer to mlan_adapter structure
234 * @param pioctl_req A pointer to ioctl request buffer
235 *
236 * @return MLAN_STATUS_PENDING --success, otherwise fail
237 */
238
wlan_11ac_ioctl_vhtcfg(IN mlan_private * pmpriv,IN t_u8 action,IN mlan_ds_11ac_vht_cfg * vht_cfg)239 mlan_status wlan_11ac_ioctl_vhtcfg(IN mlan_private *pmpriv, IN t_u8 action, IN mlan_ds_11ac_vht_cfg *vht_cfg)
240 {
241 mlan_status ret = MLAN_STATUS_SUCCESS;
242 mlan_adapter *pmadapter = pmpriv->adapter;
243 t_u16 cmd_action = 0;
244 t_u32 usr_vht_cap_info = 0;
245 t_u32 cfg_value = 0;
246 t_u32 hw_value = 0;
247 t_u8 nss = 0;
248 t_u16 no_nss_support = NO_NSS_SUPPORT;
249
250 ENTER();
251
252 #define VHT_CAP_INFO_BIT_FIELDS \
253 (MBIT(4) | MBIT(5) | MBIT(6) | MBIT(7) | MBIT(11) | MBIT(12) | MBIT(19) | MBIT(20) | MBIT(21) | MBIT(22) | \
254 MBIT(28) | MBIT(29))
255
256 if (action == (t_u8)MLAN_ACT_SET)
257 {
258 /** SET operation */
259 /** validate the user input and correct it if necessary */
260 if (pmpriv->bss_role == MLAN_BSS_ROLE_STA)
261 {
262 if (vht_cfg->txrx == 3U)
263 {
264 PRINTM(MERROR, "Configuration of VHT capabilities for TX/RX 3 is not supported in STA mode!\n");
265 return MLAN_STATUS_FAILURE;
266 }
267 }
268 if (pmpriv->bss_role == MLAN_BSS_ROLE_UAP)
269 {
270 if (vht_cfg->txrx != 3U)
271 {
272 PRINTM(MERROR, "Configuration of VHT capabilities for TX/RX %d is not supported in UAP mode!\n",
273 vht_cfg->txrx);
274
275 return MLAN_STATUS_FAILURE;
276 }
277 }
278 /** set bit fileds */
279 usr_vht_cap_info = VHT_CAP_INFO_BIT_FIELDS & vht_cfg->vht_cap_info & pmadapter->hw_dot_11ac_dev_cap;
280 /** set MAX MPDU LEN field (bit 0 - bit 1) */
281 cfg_value = GET_VHTCAP_MAXMPDULEN(vht_cfg->vht_cap_info);
282 hw_value = GET_VHTCAP_MAXMPDULEN(pmadapter->hw_dot_11ac_dev_cap);
283 SET_VHTCAP_MAXMPDULEN(usr_vht_cap_info, MIN(cfg_value, hw_value));
284 /** set CHAN Width Set field (bit 2 - bit 3) */
285 cfg_value = GET_VHTCAP_CHWDSET(vht_cfg->vht_cap_info);
286 hw_value = GET_VHTCAP_CHWDSET(pmadapter->hw_dot_11ac_dev_cap);
287 SET_VHTCAP_CHWDSET(usr_vht_cap_info, MIN(cfg_value, hw_value));
288 /** set Rx STBC field (bit 8 - bit 10) */
289 cfg_value = GET_VHTCAP_RXSTBC(vht_cfg->vht_cap_info);
290 hw_value = GET_VHTCAP_RXSTBC(pmadapter->hw_dot_11ac_dev_cap);
291 SET_VHTCAP_RXSTBC(usr_vht_cap_info, MIN(cfg_value, hw_value));
292 /** set Steering Number of BFer Ant (bit 13 - bit 15) */
293 cfg_value = GET_VHTCAP_SNBFERANT(vht_cfg->vht_cap_info);
294 hw_value = GET_VHTCAP_SNBFERANT(pmadapter->hw_dot_11ac_dev_cap);
295 SET_VHTCAP_SNBFERANT(usr_vht_cap_info, MIN(cfg_value, hw_value));
296 /** set Number of Sounding Dimension (bit 16 - bit 18) */
297 cfg_value = GET_VHTCAP_NUMSNDDM(vht_cfg->vht_cap_info);
298 hw_value = GET_VHTCAP_NUMSNDDM(pmadapter->hw_dot_11ac_dev_cap);
299 SET_VHTCAP_NUMSNDDM(usr_vht_cap_info, MIN(cfg_value, hw_value));
300 /** set Number of Max AMPDU Length Exponent (bit 23 - bit 25) */
301 cfg_value = GET_VHTCAP_MAXAMPDULENEXP(vht_cfg->vht_cap_info);
302 hw_value = GET_VHTCAP_MAXAMPDULENEXP(pmadapter->hw_dot_11ac_dev_cap);
303 SET_VHTCAP_MAXAMPDULENEXP(usr_vht_cap_info, MIN(cfg_value, hw_value));
304 /** set VHT Link Adaptation Capable (bit 26 - bit 27) */
305 cfg_value = GET_VHTCAP_LINKADPCAP(vht_cfg->vht_cap_info);
306 hw_value = GET_VHTCAP_LINKADPCAP(pmadapter->hw_dot_11ac_dev_cap);
307 SET_VHTCAP_LINKADPCAP(usr_vht_cap_info, MIN(cfg_value, hw_value));
308 /** update the user setting if it is beyond the hw capabiliteis */
309 vht_cfg->vht_cap_info = usr_vht_cap_info;
310 PRINTM(MINFO, "Set: vht cap info 0x%x\n", usr_vht_cap_info);
311
312 /** update the RX MCS map */
313 if ((vht_cfg->txrx & MLAN_RADIO_RX) != 0U)
314 {
315 /* use the previous user value */
316 if (vht_cfg->vht_rx_mcs == 0xffffffffU)
317 {
318 vht_cfg->vht_rx_mcs = GET_VHTMCS(pmadapter->usr_dot_11ac_mcs_support);
319 }
320 for (nss = 1; nss <= 8U; nss++)
321 {
322 cfg_value = GET_VHTNSSMCS(vht_cfg->vht_rx_mcs, nss);
323 hw_value = GET_DEVNSSRXMCS(pmadapter->hw_dot_11ac_mcs_support, nss);
324 if ((hw_value == NO_NSS_SUPPORT) || (cfg_value == NO_NSS_SUPPORT))
325 {
326 SET_VHTNSSMCS(vht_cfg->vht_rx_mcs, nss, no_nss_support);
327 }
328 else
329 {
330 SET_VHTNSSMCS(vht_cfg->vht_rx_mcs, nss, MIN(cfg_value, hw_value));
331 }
332 }
333 PRINTM(MINFO, "Set: vht rx mcs set 0x%08x\n", vht_cfg->vht_rx_mcs);
334 /* use the previous user value */
335 if (vht_cfg->vht_tx_mcs == 0xffffffffU)
336 {
337 vht_cfg->vht_tx_mcs = GET_VHTMCS(pmadapter->usr_dot_11ac_mcs_support >> 16);
338 }
339 for (nss = 1; nss <= 8U; nss++)
340 {
341 cfg_value = GET_VHTNSSMCS(vht_cfg->vht_tx_mcs, nss);
342 hw_value = GET_DEVNSSTXMCS(pmadapter->hw_dot_11ac_mcs_support, nss);
343 if ((hw_value == NO_NSS_SUPPORT) || (cfg_value == NO_NSS_SUPPORT))
344 {
345 SET_VHTNSSMCS(vht_cfg->vht_tx_mcs, nss, no_nss_support);
346 }
347 else
348 {
349 SET_VHTNSSMCS(vht_cfg->vht_tx_mcs, nss, MIN(cfg_value, hw_value));
350 }
351 }
352
353 PRINTM(MINFO, "Set: vht tx mcs set 0x%08x\n", vht_cfg->vht_tx_mcs);
354 if (!vht_cfg->skip_usr_11ac_mcs_cfg)
355 {
356 RESET_DEVRXMCSMAP(pmadapter->usr_dot_11ac_mcs_support);
357 pmadapter->usr_dot_11ac_mcs_support |= GET_VHTMCS(vht_cfg->vht_rx_mcs);
358 RESET_DEVTXMCSMAP(pmadapter->usr_dot_11ac_mcs_support);
359 pmadapter->usr_dot_11ac_mcs_support |= (GET_VHTMCS(vht_cfg->vht_tx_mcs) << 16);
360 PRINTM(MINFO, "Set: vht mcs set 0x%08x\n", pmadapter->usr_dot_11ac_mcs_support);
361 }
362 else
363 {
364 PRINTM(MINFO, "Skipped user 11ac mcs configuration\n");
365 vht_cfg->skip_usr_11ac_mcs_cfg = MFALSE;
366 }
367 }
368 }
369
370 if (pmpriv->bss_role == MLAN_BSS_ROLE_STA)
371 {
372 if ((vht_cfg->txrx & MLAN_RADIO_RX) != 0U)
373 {
374 /* maximum VHT configuration used in association */
375
376 if (action == (t_u8)MLAN_ACT_SET)
377 {
378 if (vht_cfg->band == BAND_SELECT_BG)
379 {
380 pmadapter->usr_dot_11ac_dev_cap_bg = usr_vht_cap_info;
381 }
382 #if CONFIG_5GHz_SUPPORT
383 else if (vht_cfg->band == BAND_SELECT_A)
384 {
385 pmadapter->usr_dot_11ac_dev_cap_a = usr_vht_cap_info;
386 }
387 #endif
388 else
389 {
390 pmadapter->usr_dot_11ac_dev_cap_bg = usr_vht_cap_info;
391 #if CONFIG_5GHz_SUPPORT
392 pmadapter->usr_dot_11ac_dev_cap_a = usr_vht_cap_info;
393 #endif
394 }
395 pmadapter->usr_dot_11ac_bw = (t_u8)vht_cfg->bwcfg;
396 }
397 else
398 {
399 /** GET operation */
400 if (vht_cfg->band == BAND_SELECT_BG)
401 {
402 vht_cfg->vht_cap_info = pmadapter->usr_dot_11ac_dev_cap_bg;
403 PRINTM(MINFO, "Get: vht cap info for 2.4GHz 0x%x\n", pmadapter->usr_dot_11ac_dev_cap_bg);
404 }
405 #if CONFIG_5GHz_SUPPORT
406 else if (vht_cfg->band == BAND_SELECT_A)
407 {
408 vht_cfg->vht_cap_info = pmadapter->usr_dot_11ac_dev_cap_a;
409 PRINTM(MINFO, "Get: vht cap info for 5GHz 0x%x\n", pmadapter->usr_dot_11ac_dev_cap_a);
410 }
411 #endif
412 else
413 {
414 PRINTM(MINFO, "Get: invalid band selection for vht cap info\n");
415 ret = MLAN_STATUS_FAILURE;
416 }
417 vht_cfg->bwcfg = pmadapter->usr_dot_11ac_bw;
418 vht_cfg->vht_rx_mcs = GET_DEVRXMCSMAP(pmadapter->usr_dot_11ac_mcs_support);
419 vht_cfg->vht_tx_mcs = GET_DEVTXMCSMAP(pmadapter->usr_dot_11ac_mcs_support);
420 vht_cfg->vht_rx_max_rate =
421 wlan_convert_mcsmap_to_maxrate(pmpriv, (t_u8)vht_cfg->band, (t_u16)vht_cfg->vht_rx_mcs);
422 vht_cfg->vht_tx_max_rate =
423 wlan_convert_mcsmap_to_maxrate(pmpriv, (t_u8)vht_cfg->band, (t_u16)vht_cfg->vht_tx_mcs);
424 }
425 LEAVE();
426 return ret;
427 }
428 }
429
430 if (action == (t_u8)MLAN_ACT_SET)
431 {
432 cmd_action = HostCmd_ACT_GEN_SET;
433 }
434 else
435 {
436 cmd_action = HostCmd_ACT_GEN_GET;
437 }
438
439 /* Send request to firmware */
440 ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_11AC_CFG, cmd_action, 0, NULL, (t_void *)vht_cfg);
441 if (ret == MLAN_STATUS_SUCCESS)
442 {
443 ret = MLAN_STATUS_PENDING;
444 }
445
446 LEAVE();
447 return ret;
448 }
449 #endif
450
451 #if 0
452 /**
453 * @brief Get/Set Operating Mode Notification cfg
454 *
455 * @param pmadapter A pointer to mlan_adapter structure
456 * @param pioctl_req A pointer to ioctl request buffer
457 *
458 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
459 */
460 static mlan_status wlan_11ac_ioctl_opermodecfg(
461 IN pmlan_adapter pmadapter,
462 IN pmlan_ioctl_req pioctl_req)
463 {
464 mlan_private *pmpriv = pmadapter->priv[pioctl_req->bss_index];
465 t_u8 hw_bw_160or8080 = 0;
466 t_u8 hw_rx_nss = 0;
467
468 ENTER();
469
470 cfg = (mlan_ds_11ac_cfg *)pioctl_req->pbuf;
471 if (pioctl_req->action == MLAN_ACT_GET) {
472 cfg->param.opermode_cfg.bw = pmpriv->usr_dot_11ac_opermode_bw;
473 cfg->param.opermode_cfg.nss = pmpriv->usr_dot_11ac_opermode_nss;
474 } else if (pioctl_req->action == MLAN_ACT_SET) {
475 hw_bw_160or8080 = GET_VHTCAP_CHWDSET(pmadapter->hw_dot_11ac_dev_cap);
476 hw_rx_nss = wlan_get_nss_num_vht_mcs(GET_DEVRXMCSMAP(pmadapter->hw_dot_11ac_mcs_support));
477 if ((((cfg->param.opermode_cfg.bw - 1) > BW_80MHZ) && !hw_bw_160or8080) ||
478 (cfg->param.opermode_cfg.nss > hw_rx_nss)) {
479 PRINTM(MERROR, "bw or nss NOT supported. HW support bw_160or8080=%d rx_nss=%d.\n",
480 hw_bw_160or8080, hw_rx_nss);
481 LEAVE();
482 return MLAN_STATUS_FAILURE;
483 }
484 pmpriv->usr_dot_11ac_opermode_bw = cfg->param.opermode_cfg.bw;
485 pmpriv->usr_dot_11ac_opermode_nss = cfg->param.opermode_cfg.nss;
486 }
487
488 LEAVE();
489 return MLAN_STATUS_SUCCESS;
490 }
491
492 /**
493 * @brief Get supported MCS set
494 *
495 * @param pmadapter A pointer to mlan_adapter structure
496 * @param pioctl_req A pointer to ioctl request buffer
497 *
498 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
499 */
500 static mlan_status wlan_11ac_ioctl_supported_mcs_set(
501 IN pmlan_adapter pmadapter,
502 IN pmlan_ioctl_req pioctl_req)
503 {
504 /*mlan_ds_11ac_cfg *cfg= MNULL;*/
505 /*int rx_mcs_supp;*/
506 /*t_u8 mcs_set[NUM_MCS_SUPP];*/
507
508 ENTER();
509 #if 0
510 if (pioctl_req->action == MLAN_ACT_SET) {
511 PRINTM(MERROR, "Set operation is not supported\n");
512 pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
513 LEAVE();
514 return MLAN_STATUS_FAILURE;
515 }
516 rx_mcs_supp = GET_11ACRXMCSSUPP(pmadapter->usr_dot_11ac_mcs_support);
517 /* Set MCS */
518 (void)__memset(pmadapter, (t_u8 *) mcs_set, 0xff, rx_mcs_supp);
519 /* Clear all the other values */
520 (void)__memset(pmadapter, (t_u8 *) &mcs_set[rx_mcs_supp], 0,
521 NUM_MCS_FIELD - rx_mcs_supp);
522 /* Set MCS32 with 40MHz support */
523 if (ISSUPP_CHANWIDTH80(pmadapter->usr_dot_11ac_dev_cap_bg)
524 #if CONFIG_5GHz_SUPPORT
525 || ISSUPP_CHANWIDTH80(pmadapter->usr_dot_11ac_dev_cap_a)
526 #endif
527 )
528 SETHT_MCS32(mcs_set);
529
530 cfg = (mlan_ds_11ac_cfg *)pioctl_req->pbuf;
531 (void)__memcpy(pmadapter, cfg->param.supported_mcs_set, mcs_set, NUM_MCS_SUPP);
532
533 #endif
534 LEAVE();
535 return MLAN_STATUS_SUCCESS;
536 }
537
538 /********************************************************
539 Global Functions
540 ********************************************************/
541
542 /**
543 * @brief This function prints the 802.11ac device capability
544 *
545 * @param pmadapter A pointer to mlan_adapter structure
546 * @param cap Capability value
547 *
548 * @return N/A
549 */
550 void wlan_show_dot11acdevcap(pmlan_adapter pmadapter, t_u32 cap)
551 {
552 ENTER();
553
554 switch (GET_VHTCAP_MAXMPDULEN(cap)) {
555 case 0x0:
556 PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = 3895 octets\n");
557 break;
558 case 0x1:
559 PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = 7991 octets\n");
560 break;
561 case 0x2:
562 PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = 11454 octets\n");
563 break;
564 default:
565 PRINTM(MINFO, "Unsupport value\n");
566 break;
567 }
568
569 PRINTM(MINFO, "GET_HW_SPEC: HTC-VHT %s\n",
570 (ISSUPP_11ACVHTHTCVHT(cap) ? "supported" : "not supported"));
571 PRINTM(MINFO, "GET_HW_SPEC: VHT TXOP PS %s\n",
572 (ISSUPP_11ACVHTTXOPPS(cap) ? "supported" : "not supported"));
573 PRINTM(MINFO, "GET_HW_SPEC: MU RX beamformee %s\n",
574 (ISSUPP_11ACMURXBEAMFORMEE(cap) ? "supported" : "not supported"));
575 PRINTM(MINFO, "GET_HW_SPEC: MU TX beamformee %s\n",
576 (ISSUPP_11ACMUTXBEAMFORMEE(cap) ? "supported" : "not supported"));
577 PRINTM(MINFO, "GET_HW_SPEC: SU RX Beamformee %s\n",
578 (ISSUPP_11ACSUBEAMFORMEE(cap) ? "supported" : "not supported"));
579 PRINTM(MINFO, "GET_HW_SPEC: SU TX Beamformer %s\n",
580 (ISSUPP_11ACSUBEAMFORMER(cap) ? "supported" : "not supported"));
581 PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
582 (ISSUPP_11ACRXSTBC(cap) ? "supported" : "not supported"));
583 PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
584 (ISSUPP_11ACTXSTBC(cap) ? "supported" : "not supported"));
585 PRINTM(MINFO, "GET_HW_SPEC: Short GI %s for 160MHz BW\n",
586 (ISSUPP_11ACSGI160(cap) ? "supported" : "not supported"));
587 PRINTM(MINFO, "GET_HW_SPEC: Short GI %s for 80MHz BW\n",
588 (ISSUPP_11ACSGI80(cap) ? "supported" : "not supported"));
589 PRINTM(MINFO, "GET_HW_SPEC: LDPC coding %s\n",
590 (ISSUPP_11ACLDPC(cap) ? "supported" : "not supported"));
591 PRINTM(MINFO, "GET_HW_SPEC: Channel BW 20/40/80/160/80+80 MHz %s\n",
592 (ISSUPP_11ACBW8080(cap) ? "supported" : "not supported"));
593 PRINTM(MINFO, "GET_HW_SPEC: Channel BW 20/40/80/160 MHz %s\n",
594 (ISSUPP_11ACBW160(cap) ? "supported" : "not supported"));
595
596 LEAVE();
597 return;
598 }
599
600 /**
601 * @brief This function prints the 802.11ac device MCS
602 *
603 * @param pmadapter A pointer to mlan_adapter structure
604 * @param support Support value
605 *
606 * @return N/A
607 */
608 void wlan_show_dot11acmcssupport(pmlan_adapter pmadapter, t_u32 support)
609 {
610 ENTER();
611
612 PRINTM(MINFO, "GET_HW_SPEC: MCSs for %2dx%2d MIMO\n", GET_DEVRXMCSMAP(support),
613 GET_DEVTXMCSMAP(support));
614
615 LEAVE();
616 return;
617 }
618
619 #endif
620
621 /**
622 * @brief This function converts the 2-bit MCS map to the highest long GI
623 * VHT PPDU data rate
624 *
625 * @param priv A pointer to mlan_private structure
626 * @param bands Supported bands
627 * @param mcs_map 2-bit MCS map
628 *
629 * @return the max data rate for long GI
630 */
wlan_convert_mcsmap_to_maxrate(mlan_private * priv,t_u8 bands,t_u16 mcs_map)631 t_u16 wlan_convert_mcsmap_to_maxrate(mlan_private *priv, t_u8 bands, t_u16 mcs_map)
632 {
633 mlan_adapter *pmadapter = priv->adapter;
634 t_u8 i;
635 t_u8 nss;
636 t_u8 max_mcs;
637 t_u16 max_rate = 0;
638 t_u32 usr_vht_cap_info = 0;
639 t_u32 usr_dot_11n_dev_cap;
640
641 /* tables of the MCS map to the highest data rate (in Mbps)
642 * supported for long GI */
643 t_u16 max_rate_lgi_20MHZ[8][3] = {
644 {0x41, 0x4E, 0x0}, /* NSS = 1 */
645 {0x82, 0x9C, 0x0}, /* NSS = 2 */
646 {0xC3, 0xEA, 0x104}, /* NSS = 3 */
647 {0x104, 0x138, 0x0}, /* NSS = 4 */
648 {0x145, 0x186, 0x0}, /* NSS = 5 */
649 {0x186, 0x1D4, 0x208}, /* NSS = 6 */
650 {0x1C7, 0x222, 0x0}, /* NSS = 7 */
651 {0x208, 0x270, 0x0} /* NSS = 8 */
652 };
653
654 t_u16 max_rate_lgi_40MHZ[8][3] = {
655 {0x87, 0xA2, 0xB4}, /* NSS = 1 */
656 {0x10E, 0x144, 0x168}, /* NSS = 2 */
657 {0x195, 0x1E6, 0x21C}, /* NSS = 3 */
658 {0x21C, 0x288, 0x2D0}, /* NSS = 4 */
659 {0x2A3, 0x32A, 0x384}, /* NSS = 5 */
660 {0x32A, 0x3CC, 0x438}, /* NSS = 6 */
661 {0x3B1, 0x46E, 0x4EC}, /* NSS = 7 */
662 {0x438, 0x510, 0x5A0} /* NSS = 8 */
663 };
664
665 t_u16 max_rate_lgi_80MHZ[8][3] = {
666 {0x124, 0x15F, 0x186}, /* NSS = 1 */
667 {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
668 {0x36D, 0x41D, 0x492}, /* NSS = 3 */
669 {0x492, 0x57C, 0x618}, /* NSS = 4 */
670 {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
671 {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
672 {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
673 {0x924, 0xAF8, 0xC30} /* NSS = 8 */
674 };
675 t_u16 max_rate_lgi_160MHZ[8][3] = {
676 {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
677 {0x492, 0x57C, 0x618}, /* NSS = 2 */
678 {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
679 {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
680 {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
681 {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
682 {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
683 {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
684 };
685
686 #if CONFIG_5GHz_SUPPORT
687 if ((bands & BAND_AAC) != 0U)
688 {
689 usr_vht_cap_info = pmadapter->usr_dot_11ac_dev_cap_a;
690 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_a;
691 }
692 else
693 {
694 #endif
695 usr_vht_cap_info = pmadapter->usr_dot_11ac_dev_cap_bg;
696 usr_dot_11n_dev_cap = pmadapter->usr_dot_11n_dev_cap_bg;
697 #if CONFIG_5GHz_SUPPORT
698 }
699 #endif
700
701 /* find the max NSS supported */
702 nss = 0;
703 for (i = 0; i < 8U; i++)
704 {
705 max_mcs = (t_u8)((mcs_map >> (2U * i)) & 0x3U);
706 if (max_mcs < 3U)
707 {
708 nss = i;
709 }
710 }
711
712 max_mcs = (t_u8)((mcs_map >> (2U * nss)) & 0x3U);
713 /* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9*/
714 if (max_mcs >= 3U)
715 {
716 max_mcs = (t_u8)2U;
717 }
718
719 if (GET_VHTCAP_CHWDSET(usr_vht_cap_info) != 0U)
720 {
721 /* support 160 MHz */
722 max_rate = max_rate_lgi_160MHZ[nss][max_mcs];
723 if (max_mcs >= 1U && max_rate == 0U)
724 {
725 /* MCS9 is not supported in NSS6 */
726 max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1U];
727 }
728 }
729 else
730 {
731 if (pmadapter->usr_dot_11ac_bw == BW_FOLLOW_VHTCAP)
732 {
733 max_rate = max_rate_lgi_80MHZ[nss][max_mcs];
734 if (max_mcs >= 1U && max_rate == 0U)
735 {
736 /* MCS9 is not supported in NSS3 */
737 max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1U];
738 }
739 }
740 else
741 {
742 if (ISSUPP_CHANWIDTH40(usr_dot_11n_dev_cap) != 0U)
743 {
744 max_rate = max_rate_lgi_40MHZ[nss][max_mcs];
745 }
746 else
747 {
748 max_rate = max_rate_lgi_20MHZ[nss][max_mcs];
749 /* MCS9 is not supported in NSS1/2/4/5/7/8 */
750 if (max_mcs >= 1U && max_rate == 0U)
751 {
752 max_rate = max_rate_lgi_20MHZ[nss][max_mcs - 1U];
753 }
754 }
755 }
756 }
757 PRINTM(MCMND, "max_rate=%dM\n", max_rate);
758 return max_rate;
759 }
760
761 /**
762 * @brief This function fills the VHT cap tlv out put format is LE, not CPU
763 *
764 * @param priv A pointer to mlan_private structure
765 * @param pvht_cap A pointer to MrvlIETypes_HTCap_t structure
766 * @param bands Band configuration
767 * @param flag TREU--pvht_cap has the setting for resp
768 * MFALSE -- pvht_cap is clean
769 * @return N/A
770 */
wlan_fill_vht_cap_tlv(mlan_private * priv,MrvlIETypes_VHTCap_t * pvht_cap,t_u16 bands,t_u8 flag)771 void wlan_fill_vht_cap_tlv(mlan_private *priv, MrvlIETypes_VHTCap_t *pvht_cap, t_u16 bands, t_u8 flag)
772 {
773 mlan_adapter *pmadapter = priv->adapter;
774 t_u16 mcs_map_user = 0;
775 t_u16 mcs_map_resp = 0;
776 t_u32 mcs_map_result = 0U;
777 t_u16 mcs_user = 0;
778 t_u16 mcs_resp = 0;
779 t_u16 nss;
780 t_u16 no_nss_support = NO_NSS_SUPPORT;
781
782 ENTER();
783
784 /* Fill VHT cap info */
785 wlan_fill_cap_info(priv, &pvht_cap->vht_cap, bands);
786 pvht_cap->vht_cap.vht_cap_info = wlan_cpu_to_le32(pvht_cap->vht_cap.vht_cap_info);
787
788 /* Fill VHT MCS Set */
789 /* rx MCS Set, find the minimum of the user rx mcs and ap rx mcs*/
790 mcs_map_resp = mcs_map_user = (t_u16)GET_DEVRXMCSMAP(pmadapter->usr_dot_11ac_mcs_support);
791 if (flag != 0U)
792 {
793 mcs_map_resp = wlan_le16_to_cpu(pvht_cap->vht_cap.mcs_sets.rx_mcs_map);
794 }
795 mcs_map_result = 0U;
796 for (nss = 1; nss <= 8U; nss++)
797 {
798 mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
799 mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
800 if ((mcs_user == NO_NSS_SUPPORT) || (mcs_resp == NO_NSS_SUPPORT))
801 {
802 SET_VHTNSSMCS(mcs_map_result, nss, no_nss_support);
803 }
804 else
805 {
806 SET_VHTNSSMCS(mcs_map_result, nss, MIN(mcs_user, mcs_resp));
807 }
808 }
809 /* rx MCS map */
810 pvht_cap->vht_cap.mcs_sets.rx_mcs_map = wlan_cpu_to_le16(mcs_map_result);
811
812 /* rx highest rate */
813 pvht_cap->vht_cap.mcs_sets.rx_max_rate = wlan_convert_mcsmap_to_maxrate(priv, (t_u8)bands, (t_u16)mcs_map_result);
814 pvht_cap->vht_cap.mcs_sets.rx_max_rate = wlan_cpu_to_le16(pvht_cap->vht_cap.mcs_sets.rx_max_rate);
815
816 /* tx MCS Set find the minimum of the user tx mcs and ap tx mcs */
817 mcs_map_resp = mcs_map_user = (t_u16)GET_DEVTXMCSMAP(pmadapter->usr_dot_11ac_mcs_support);
818 if (flag != 0U)
819 {
820 mcs_map_resp = wlan_le16_to_cpu(pvht_cap->vht_cap.mcs_sets.tx_mcs_map);
821 }
822 mcs_map_result = 0U;
823 for (nss = 1; nss <= 8U; nss++)
824 {
825 mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
826 mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
827 if ((mcs_user == NO_NSS_SUPPORT) || (mcs_resp == NO_NSS_SUPPORT))
828 {
829 SET_VHTNSSMCS(mcs_map_result, nss, no_nss_support);
830 }
831 else
832 {
833 SET_VHTNSSMCS(mcs_map_result, nss, MIN(mcs_user, mcs_resp));
834 }
835 }
836
837 /* tx MCS map */
838 pvht_cap->vht_cap.mcs_sets.tx_mcs_map = wlan_cpu_to_le16(mcs_map_result);
839 /* tx highest rate */
840 pvht_cap->vht_cap.mcs_sets.tx_max_rate = wlan_convert_mcsmap_to_maxrate(priv, (t_u8)bands, (t_u16)mcs_map_result);
841 pvht_cap->vht_cap.mcs_sets.tx_max_rate = wlan_cpu_to_le16(pvht_cap->vht_cap.mcs_sets.tx_max_rate);
842
843 LEAVE();
844 return;
845 }
846
847 #if 0
848 /**
849 * @brief This function fills the VHT cap tlv out put format is CPU
850 *
851 * @param priv A pointer to mlan_private structure
852 * @param pvht_cap A pointer to MrvlIETypes_HTCap_t structure
853 * @param bands Band configuration
854 *
855 * @return N/A
856 */
857 void wlan_fill_vht_cap_ie(mlan_private *priv,
858 IEEEtypes_VHTCap_t *pvht_cap, t_u16 bands)
859 {
860 ENTER();
861
862 pvht_cap->ieee_hdr.element_id = VHT_CAPABILITY;
863 pvht_cap->ieee_hdr.len = sizeof(VHT_capa_t);
864
865 /* Fill VHT cap info */
866 wlan_fill_cap_info(priv, &pvht_cap->vht_cap, bands);
867
868 /* rx MCS map */
869 pvht_cap->vht_cap.mcs_sets.rx_mcs_map =
870 GET_DEVRXMCSMAP(priv->usr_dot_11ac_mcs_support);
871
872 /* rx highest rate */
873 pvht_cap->vht_cap.mcs_sets.rx_max_rate =
874 wlan_convert_mcsmap_to_maxrate(priv, bands, pvht_cap->vht_cap.mcs_sets.rx_mcs_map);
875
876 /* tx MCS map */
877 pvht_cap->vht_cap.mcs_sets.tx_mcs_map = GET_DEVTXMCSMAP(priv->usr_dot_11ac_mcs_support);
878 /* tx highest rate */
879 pvht_cap->vht_cap.mcs_sets.tx_max_rate =
880 wlan_convert_mcsmap_to_maxrate(priv, bands,pvht_cap->vht_cap.mcs_sets.tx_mcs_map);
881
882 LEAVE();
883 return;
884 }
885
886 #ifdef HOST_TDLS_SUPPORT
887 /*
888 * @brief This function check if AP is in 11ac mode
889 *
890 * @param priv A pointer to mlan_private structure
891 *
892 * @return MTRUE/MFALSE
893 */
894 t_u8 wlan_is_ap_in_11ac_mode(mlan_private *priv)
895 {
896 BSSDescriptor_t *pbss_desc;
897 IEEEtypes_VHTOprat_t *vht_oprat = MNULL;
898 pbss_desc = &priv->curr_bss_params.bss_descriptor;
899 #ifdef ENABLE_SAVE_SCAN_RESP
900 vht_oprat = pbss_desc->pvht_oprat;
901 if(!pbss_desc->pvht_cap)
902 #else
903 vht_oprat = &pbss_desc->vht_oprat;
904 if(pbss_desc->vht_cap.ieee_hdr.element_id != VHT_CAPABILITY)
905 #endif
906 return MFALSE;
907 if(vht_oprat && (vht_oprat->ieee_hdr.element_id == VHT_OPERATION)) {
908 if(vht_oprat->chan_width == VHT_OPER_CHWD_20_40MHZ)
909 return MFALSE;
910 else
911 return MTRUE;
912 }
913 else
914 return MFALSE;
915 }
916
917
918 /**
919 * @brief This function fills the VHTOperation ie out put format is CPU
920 *
921 * @param priv A pointer to mlan_private structure
922 * @param vht_oprat A pointer to IEEEtypes_VHTOprat_t structure
923 * @param sta_ptr A pointer to sta_node
924 *
925 * @return N/A
926 */
927 void wlan_fill_tdls_vht_oprat_ie(mlan_private *priv, IEEEtypes_VHTOprat_t *vht_oprat, sta_node *sta_ptr)
928 {
929 t_u8 supp_chwd_set;
930 t_u8 peer_supp_chwd_set;
931 t_u8 ap_supp_chwd_set;
932 t_u32 usr_vht_cap_info;
933
934 t_u16 mcs_map_user = 0;
935 t_u16 mcs_map_resp = 0;
936 t_u16 mcs_map_result = 0;
937 t_u16 mcs_user = 0;
938 t_u16 mcs_resp = 0;
939 t_u16 nss;
940 t_u16 no_nss_support = NO_NSS_SUPPORT;
941 t_u8 chan_bw = 0;
942 BSSDescriptor_t *pbss_desc;
943 IEEEtypes_VHTCap_t *pvht_cap = &sta_ptr->vht_cap;
944 IEEEtypes_VHTCap_t *ap_vht_cap = MNULL;
945 ENTER();
946
947 pbss_desc = &priv->curr_bss_params.bss_descriptor;
948
949 /* Check if AP is in 11ac mode */
950 if(MFALSE == wlan_is_ap_in_11ac_mode(priv)){
951 if(sta_ptr->ExtCap.ieee_hdr.element_id != EXT_CAPABILITY){
952 PRINTM(MMSG,"No Peer's Ext_cap info\n");
953 return;
954 }
955 if(!ISSUPP_EXTCAP_TDLS_WIDER_BANDWIDTH(sta_ptr->ExtCap.ext_cap)){
956 PRINTM(MMSG,"Peer don't support Wider Bandwitch in Ext_cap\n");
957 return;
958 }
959 }
960 else{
961 #ifdef ENABLE_SAVE_SCAN_RESP
962 ap_vht_cap = pbss_desc->pvht_cap;
963 #else
964 ap_vht_cap = &pbss_desc->vht_cap;
965 #endif
966 }
967
968 vht_oprat->ieee_hdr.element_id = VHT_OPERATION;
969 vht_oprat->ieee_hdr.len = sizeof(IEEEtypes_VHTOprat_t) - sizeof(IEEEtypes_Header_t);
970
971 #if CONFIG_5GHz_SUPPORT
972 if (pbss_desc->bss_band & BAND_A)
973 usr_vht_cap_info= priv->usr_dot_11ac_dev_cap_a;
974 else
975 #endif
976 usr_vht_cap_info = priv->usr_dot_11ac_dev_cap_bg;
977
978 /* find the minmum bandwith between AP/TDLS peers */
979 supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
980 peer_supp_chwd_set = GET_VHTCAP_CHWDSET(pvht_cap->vht_cap.vht_cap_info);
981 supp_chwd_set = MIN(supp_chwd_set, peer_supp_chwd_set);
982
983 /* We need check AP's bandwidth when TDLS_WIDER_BANDWIDTH is off */
984 if(ap_vht_cap && !ISSUPP_EXTCAP_TDLS_WIDER_BANDWIDTH(sta_ptr->ExtCap.ext_cap)){
985 ap_supp_chwd_set = GET_VHTCAP_CHWDSET(ap_vht_cap->vht_cap.vht_cap_info);
986 supp_chwd_set = MIN(supp_chwd_set, ap_supp_chwd_set);
987 }
988 switch(supp_chwd_set){
989 case VHT_CAP_CHWD_80MHZ:
990 vht_oprat->chan_width = VHT_OPER_CHWD_80MHZ;
991 break;
992 case VHT_CAP_CHWD_160MHZ:
993 vht_oprat->chan_width = VHT_OPER_CHWD_160MHZ;
994 break;
995 case VHT_CAP_CHWD_80_80MHZ:
996 vht_oprat->chan_width = VHT_OPER_CHWD_80_80MHZ;
997 break;
998
999 }
1000
1001 /* Fill BASIC VHT MCS and NSS Set */
1002 /* rx MCS Set, find the minimum of the user rx mcs and peer rx mcs*/
1003 mcs_map_user = GET_DEVRXMCSMAP(priv->usr_dot_11ac_mcs_support);
1004 mcs_map_resp = pvht_cap->vht_cap.mcs_sets.rx_mcs_map;
1005 mcs_map_result = 0;
1006 for (nss = 1; nss <= 8; nss++) {
1007 mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
1008 mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
1009 if ((mcs_user == NO_NSS_SUPPORT) || (mcs_resp == NO_NSS_SUPPORT))
1010 SET_VHTNSSMCS(mcs_map_result, nss, no_nss_support);
1011 else
1012 SET_VHTNSSMCS(mcs_map_result, nss, MIN(mcs_user, mcs_resp));
1013 }
1014 /* Basic MCS map */
1015 vht_oprat->basic_MCS_map = mcs_map_result;
1016 switch(vht_oprat->chan_width){
1017 case VHT_OPER_CHWD_80MHZ:
1018 chan_bw = CHANNEL_BW_80MHZ;
1019 break;
1020 case VHT_OPER_CHWD_160MHZ:
1021 chan_bw = CHANNEL_BW_160MHZ;
1022 break;
1023 case VHT_OPER_CHWD_80_80MHZ:
1024 chan_bw = CHANNEL_BW_80MHZ;
1025 break;
1026 }
1027 vht_oprat->chan_center_freq_1 = wlan_get_center_freq_idx(priv,BAND_AAC,pbss_desc->channel, chan_bw);
1028
1029 LEAVE();
1030 return;
1031 }
1032 #endif
1033 #endif
1034
1035 /**
1036 * @brief This function append the 802_11AC tlv
1037 *
1038 * @param pmpriv A pointer to mlan_private structure
1039 * @param pbss_desc A pointer to BSSDescriptor_t structure
1040 * @param ppbuffer A Pointer to command buffer pointer
1041 *
1042 * @return bytes added to the buffer
1043 */
wlan_cmd_append_11ac_tlv(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc,t_u8 ** ppbuffer)1044 int wlan_cmd_append_11ac_tlv(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer)
1045 {
1046 pmlan_adapter pmadapter = pmpriv->adapter;
1047 MrvlIETypes_VHTCap_t *pvht_cap;
1048 MrvlIETypes_OperModeNtf_t *pmrvl_oper_mode;
1049 t_u16 mcs_map_user = 0;
1050 t_u16 nss;
1051 #ifdef ADHOC_11N
1052 MrvlIETypes_VHTOprat_t *pvht_op;
1053 t_u8 supp_chwd_set;
1054 t_u32 usr_vht_cap_info;
1055 #endif
1056 int ret_len = 0;
1057
1058 ENTER();
1059
1060 /* Null Checks */
1061 if (ppbuffer == MNULL)
1062 {
1063 LEAVE();
1064 return 0;
1065 }
1066 if (*ppbuffer == MNULL)
1067 {
1068 LEAVE();
1069 return 0;
1070 }
1071 /* VHT Capabilities IE */
1072 if (pbss_desc->pvht_cap != MNULL && wlan_get_nss_vht_mcs(pbss_desc->pvht_cap->vht_cap.mcs_sets.rx_mcs_map) != 0U)
1073 {
1074 pvht_cap = (MrvlIETypes_VHTCap_t *)(void *)*ppbuffer;
1075 (void)__memset(pmadapter, pvht_cap, 0, sizeof(MrvlIETypes_VHTCap_t));
1076 pvht_cap->header.type = wlan_cpu_to_le16(VHT_CAPABILITY);
1077 pvht_cap->header.len = (t_u16)sizeof(VHT_capa_t);
1078 (void)__memcpy(pmadapter, (t_u8 *)pvht_cap + sizeof(MrvlIEtypesHeader_t),
1079 (t_u8 *)pbss_desc->pvht_cap + sizeof(IEEEtypes_Header_t), pvht_cap->header.len);
1080
1081 wlan_fill_vht_cap_tlv(pmpriv, pvht_cap, pbss_desc->bss_band, (t_u8)MTRUE);
1082 if (wlan_use_non_default_ht_vht_cap(pbss_desc))
1083 {
1084 /* Indicate 3 STS in VHT cap info */
1085 pvht_cap->vht_cap.vht_cap_info = ((pvht_cap->vht_cap.vht_cap_info & (~(0x7 << 13))) | (0x2 << 13));
1086 }
1087
1088 HEXDUMP("VHT_CAPABILITIES IE", (t_u8 *)pvht_cap, sizeof(MrvlIETypes_VHTCap_t));
1089 *ppbuffer += sizeof(MrvlIETypes_VHTCap_t);
1090 ret_len += (int)sizeof(MrvlIETypes_VHTCap_t);
1091 pvht_cap->header.len = wlan_cpu_to_le16(pvht_cap->header.len);
1092 }
1093 else
1094 {
1095 LEAVE();
1096 return 0;
1097 }
1098
1099 /* Operating Mode Notification IE */
1100 pmrvl_oper_mode = (MrvlIETypes_OperModeNtf_t *)(void *)*ppbuffer;
1101 (void)__memset(pmadapter, pmrvl_oper_mode, 0, sizeof(MrvlIETypes_OperModeNtf_t));
1102 pmrvl_oper_mode->header.type = wlan_cpu_to_le16(OPER_MODE_NTF);
1103 pmrvl_oper_mode->header.len = (t_u16)sizeof(t_u8);
1104
1105 if (pmadapter->usr_dot_11ac_opermode_bw != 0U || pmadapter->usr_dot_11ac_opermode_nss != 0U)
1106 {
1107 pmrvl_oper_mode->oper_mode |= (pmadapter->usr_dot_11ac_opermode_nss - 1U) << 4U;
1108 pmrvl_oper_mode->oper_mode |= pmadapter->usr_dot_11ac_opermode_bw - 1U;
1109 if ((pbss_desc->bss_band & BAND_G) != 0U)
1110 {
1111 if (!(IS_OPER_MODE_20M(pmrvl_oper_mode->oper_mode)))
1112 {
1113 if ((pbss_desc->pht_cap->ht_cap.ht_cap_info & MBIT(1)) != 0U)
1114 {
1115 SET_OPER_MODE_40M(pmrvl_oper_mode->oper_mode);
1116 }
1117 else
1118 {
1119 SET_OPER_MODE_20M(pmrvl_oper_mode->oper_mode);
1120 }
1121 }
1122 }
1123 }
1124 else
1125 {
1126 /** set default bandwidth:80M*/
1127 SET_OPER_MODE_80M(pmrvl_oper_mode->oper_mode);
1128
1129 mcs_map_user = (t_u16)GET_DEVRXMCSMAP(pmadapter->usr_dot_11ac_mcs_support);
1130 nss = wlan_get_nss_num_vht_mcs(mcs_map_user);
1131 pmrvl_oper_mode->oper_mode |= (t_u8)(nss - 1U) << 4U;
1132
1133 switch (pbss_desc->curr_bandwidth)
1134 {
1135 case BW_20MHZ:
1136 SET_OPER_MODE_20M(pmrvl_oper_mode->oper_mode);
1137 break;
1138 case BW_40MHZ:
1139 SET_OPER_MODE_40M(pmrvl_oper_mode->oper_mode);
1140 break;
1141 case BW_80MHZ:
1142 default:
1143 PRINTM(MINFO, "Unexpected bandwidth.\n");
1144 break;
1145 }
1146 }
1147 HEXDUMP("OPER MODE NTF IE", (t_u8 *)pmrvl_oper_mode, sizeof(MrvlIETypes_OperModeNtf_t));
1148 *ppbuffer += sizeof(MrvlIETypes_OperModeNtf_t);
1149 ret_len += (int)sizeof(MrvlIETypes_OperModeNtf_t);
1150 pmrvl_oper_mode->header.len = wlan_cpu_to_le16(pmrvl_oper_mode->header.len);
1151
1152 LEAVE();
1153 return ret_len;
1154 }
1155
1156 #if 0
1157 /**
1158 * @brief 11ac configuration handler
1159 *
1160 * @param pmadapter A pointer to mlan_adapter structure
1161 * @param pioctl_req A pointer to ioctl request buffer
1162 *
1163 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
1164 */
1165 mlan_status wlan_11ac_cfg_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
1166 {
1167 mlan_status status = MLAN_STATUS_SUCCESS;
1168 mlan_ds_11ac_cfg *cfg = MNULL;
1169
1170 ENTER();
1171
1172 if (pioctl_req->buf_len < sizeof(mlan_ds_11ac_cfg)) {
1173 PRINTM(MINFO, "MLAN bss IOCTL length is too short.\n");
1174 pioctl_req->data_read_written = 0;
1175 pioctl_req->buf_len_needed = sizeof(mlan_ds_11ac_cfg);
1176 pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
1177 LEAVE();
1178 return MLAN_STATUS_RESOURCE;
1179 }
1180 cfg = (mlan_ds_11ac_cfg *)pioctl_req->pbuf;
1181 switch (cfg->sub_command) {
1182 case MLAN_OID_11AC_VHT_CFG:
1183 status = wlan_11ac_ioctl_vhtcfg(pmadapter, pioctl_req);
1184 break;
1185 case MLAN_OID_11AC_CFG_SUPPORTED_MCS_SET:
1186 status = wlan_11ac_ioctl_supported_mcs_set(pmadapter, pioctl_req);
1187 break;
1188 case MLAN_OID_11AC_OPERMODE_CFG:
1189 status = wlan_11ac_ioctl_opermodecfg(pmadapter, pioctl_req);
1190 break;
1191 default:
1192 pioctl_req->status_code = MLAN_ERROR_IOCTL_INVALID;
1193 status = MLAN_STATUS_FAILURE;
1194 break;
1195 }
1196 LEAVE();
1197 return status;
1198 }
1199 #endif
1200
1201 /**
1202 * @brief This function prepares 11ac cfg command
1203 *
1204 * @param pmpriv A pointer to mlan_private structure
1205 * @param cmd A pointer to HostCmd_DS_COMMAND structure
1206 * @param cmd_action the action: GET or SET
1207 * @param pdata_buf A pointer to data buffer
1208 * @return MLAN_STATUS_SUCCESS
1209 */
wlan_cmd_11ac_cfg(IN pmlan_private pmpriv,IN HostCmd_DS_COMMAND * cmd,IN t_u16 cmd_action,IN t_void * pdata_buf)1210 mlan_status wlan_cmd_11ac_cfg(IN pmlan_private pmpriv,
1211 IN HostCmd_DS_COMMAND *cmd,
1212 IN t_u16 cmd_action,
1213 IN t_void *pdata_buf)
1214 {
1215 HostCmd_DS_11AC_CFG *vhtcfg = &cmd->params.vhtcfg;
1216 mlan_ds_11ac_vht_cfg *vht_cfg = (mlan_ds_11ac_vht_cfg *)pdata_buf;
1217
1218 ENTER();
1219 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11AC_CFG);
1220 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11AC_CFG) + S_DS_GEN);
1221 if (pmpriv->bss_type == MLAN_BSS_TYPE_UAP)
1222 {
1223 cmd->seq_num = (t_u16)(0x01U) << 12;
1224 }
1225 vhtcfg->action = wlan_cpu_to_le16(cmd_action);
1226 vhtcfg->band_config = (t_u8)(vht_cfg->band & 0xFFU);
1227 vhtcfg->misc_config = (t_u8)(vht_cfg->txrx & 0x3U);
1228 if (vhtcfg->misc_config != 2U)
1229 {
1230 vhtcfg->misc_config |= (t_u8)(vht_cfg->bwcfg << 2);
1231 }
1232
1233 vhtcfg->vht_cap_info = wlan_cpu_to_le32(vht_cfg->vht_cap_info);
1234 vht_cfg->vht_rx_mcs = wlan_cpu_to_le32(vht_cfg->vht_rx_mcs);
1235 (void)__memcpy(pmpriv->adapter, &vhtcfg->vht_supp_mcs_set[0], &vht_cfg->vht_rx_mcs, sizeof(t_u32));
1236 vht_cfg->vht_tx_mcs = wlan_cpu_to_le32(vht_cfg->vht_tx_mcs);
1237 (void)__memcpy(pmpriv->adapter, &vhtcfg->vht_supp_mcs_set[4], &vht_cfg->vht_tx_mcs, sizeof(t_u32));
1238 LEAVE();
1239 return MLAN_STATUS_SUCCESS;
1240 }
1241
1242 #if 0
1243 /**
1244 * @brief This function handles the command response of 11ac cfg
1245 *
1246 * @param pmpriv A pointer to mlan_private structure
1247 * @param resp A pointer to HostCmd_DS_COMMAND
1248 * @param pioctl_buf A pointer to mlan_ioctl_req structure
1249 *
1250 * @return MLAN_STATUS_SUCCESS
1251 */
1252 mlan_status wlan_ret_11ac_cfg(
1253 IN pmlan_private pmpriv,
1254 IN HostCmd_DS_COMMAND *resp,
1255 IN mlan_ioctl_req *pioctl_buf)
1256 {
1257 pmlan_adapter pmadapter = pmpriv->adapter;
1258 mlan_ds_11ac_cfg *cfg = MNULL;
1259 HostCmd_DS_11AC_CFG *vhtcfg = &resp->params.vhtcfg;
1260
1261 ENTER();
1262 if (pioctl_buf && (wlan_le16_to_cpu(vhtcfg->action) == HostCmd_ACT_GEN_GET)) {
1263 cfg = (mlan_ds_11ac_cfg *)pioctl_buf->pbuf;
1264 cfg->param.vht_cfg.band = vhtcfg->band_config;
1265 cfg->param.vht_cfg.txrx = vhtcfg->misc_config & 0x03;
1266 if (cfg->param.vht_cfg.txrx & 0x1)
1267 cfg->param.vht_cfg.bwcfg = (vhtcfg->misc_config & 0x04) >> 2;
1268 else
1269 cfg->param.vht_cfg.bwcfg = 0;
1270
1271 cfg->param.vht_cfg.vht_cap_info = wlan_le32_to_cpu(vhtcfg->vht_cap_info);
1272 (void)__memcpy(pmadapter, &cfg->param.vht_cfg.vht_rx_mcs,
1273 &vhtcfg->vht_supp_mcs_set[0], sizeof(t_u32));
1274 cfg->param.vht_cfg.vht_rx_mcs =
1275 wlan_le32_to_cpu(cfg->param.vht_cfg.vht_rx_mcs);
1276 (void)__memcpy(pmadapter, &cfg->param.vht_cfg.vht_tx_mcs,
1277 &vhtcfg->vht_supp_mcs_set[4], sizeof(t_u32));
1278 cfg->param.vht_cfg.vht_tx_mcs =
1279 wlan_le32_to_cpu(cfg->param.vht_cfg.vht_tx_mcs);
1280 cfg->param.vht_cfg.vht_rx_max_rate =
1281 wlan_convert_mcsmap_to_maxrate(pmpriv,cfg->param.vht_cfg.band,cfg->param.vht_cfg.vht_rx_mcs);
1282 cfg->param.vht_cfg.vht_tx_max_rate =
1283 wlan_convert_mcsmap_to_maxrate(pmpriv, cfg->param.vht_cfg.band,cfg->param.vht_cfg.vht_tx_mcs);
1284 }
1285 LEAVE();
1286 return MLAN_STATUS_SUCCESS;
1287 }
1288
1289
1290 void wlan_update_11ac_cap(mlan_private * pmpriv){
1291
1292 mlan_adapter* pmadapter = pmpriv->adapter;
1293
1294 pmpriv->usr_dot_11ac_mcs_support = pmadapter->hw_dot_11ac_mcs_support;
1295 pmpriv->usr_dot_11ac_dev_cap_bg =
1296 pmadapter->hw_dot_11ac_dev_cap & ~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
1297 #if CONFIG_5GHz_SUPPORT
1298 pmpriv->usr_dot_11ac_dev_cap_a =
1299 pmadapter->hw_dot_11ac_dev_cap & ~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
1300 #endif
1301 pmpriv->usr_dot_11ac_bw = BW_FOLLOW_VHTCAP;
1302 }
1303 #endif
1304
1305 /**
1306 * @brief This function check if 11AC is allowed in bandcfg
1307 *
1308 * @param pmpriv A pointer to mlan_private structure
1309 * @param bss_band bss band
1310 *
1311 * @return 0--not allowed, other value allowed
1312 */
wlan_11ac_bandconfig_allowed(mlan_private * pmpriv,t_u16 bss_band)1313 t_u8 wlan_11ac_bandconfig_allowed(mlan_private *pmpriv, t_u16 bss_band)
1314 {
1315 if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS)
1316 {
1317 if ((bss_band & BAND_G) != 0U)
1318 {
1319 return (t_u8)(pmpriv->adapter->adhoc_start_band & BAND_GAC);
1320 }
1321 #if CONFIG_5GHz_SUPPORT
1322 else if ((bss_band & BAND_A) != 0U)
1323 {
1324 return (t_u8)(pmpriv->adapter->adhoc_start_band & BAND_AAC);
1325 }
1326 else
1327 { /* Do Nothing */
1328 }
1329 #endif
1330 }
1331 else
1332 {
1333 if ((bss_band & BAND_G) != 0U)
1334 {
1335 return (t_u8)(pmpriv->config_bands & BAND_GAC);
1336 }
1337 #if CONFIG_5GHz_SUPPORT
1338 else if ((bss_band & BAND_A) != 0U)
1339 {
1340 return (t_u8)(pmpriv->config_bands & BAND_AAC);
1341 }
1342 else
1343 { /* Do Nothing */
1344 }
1345 #endif
1346 }
1347 return 0;
1348 }
1349