1 /******************************************************************************
2 *
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *****************************************************************************/
15 #define _RTW_BEAMFORMING_C_
16
17 #include <drv_types.h>
18 #include <hal_data.h>
19
20 #ifdef CONFIG_BEAMFORMING
21
22 #ifdef RTW_BEAMFORMING_VERSION_2
23
24 struct ndpa_sta_info {
25 u16 aid:12;
26 u16 feedback_type:1;
27 u16 nc_index:3;
28 };
29
_get_txvector_parameter(PADAPTER adapter,struct sta_info * sta,u8 * g_id,u16 * p_aid)30 static void _get_txvector_parameter(PADAPTER adapter, struct sta_info *sta, u8 *g_id, u16 *p_aid)
31 {
32 struct mlme_priv *mlme;
33 u16 aid;
34 u8 *bssid;
35 u16 val16;
36 u8 i;
37
38
39 mlme = &adapter->mlmepriv;
40
41 if (check_fwstate(mlme, WIFI_AP_STATE)) {
42 /*
43 * Sent by an AP and addressed to a STA associated with that AP
44 * or sent by a DLS or TDLS STA in a direct path to
45 * a DLS or TDLS peer STA
46 */
47
48 aid = sta->cmn.aid;
49 bssid = adapter_mac_addr(adapter);
50 RTW_INFO("%s: AID=0x%x BSSID=" MAC_FMT "\n",
51 __FUNCTION__, sta->cmn.aid, MAC_ARG(bssid));
52
53 /* AID[0:8] */
54 aid &= 0x1FF;
55 /* BSSID[44:47] xor BSSID[40:43] */
56 val16 = ((bssid[5] & 0xF0) >> 4) ^ (bssid[5] & 0xF);
57 /* (dec(AID[0:8]) + dec(BSSID)*2^5) mod 2^9 */
58 *p_aid = (aid + (val16 << 5)) & 0x1FF;
59 *g_id = 63;
60 } else if ((check_fwstate(mlme, WIFI_ADHOC_STATE) == _TRUE)
61 || (check_fwstate(mlme, WIFI_ADHOC_MASTER_STATE) == _TRUE)) {
62 /*
63 * Otherwise, includes
64 * 1. Sent to an IBSS STA
65 * 2. Sent by an AP to a non associated STA
66 * 3. Sent to a STA for which it is not known
67 * which condition is applicable
68 */
69 *p_aid = 0;
70 *g_id = 63;
71 } else {
72 /* Addressed to AP */
73 bssid = sta->cmn.mac_addr;
74 RTW_INFO("%s: BSSID=" MAC_FMT "\n", __FUNCTION__, MAC_ARG(bssid));
75
76 /* BSSID[39:47] */
77 *p_aid = (bssid[5] << 1) | (bssid[4] >> 7);
78 *g_id = 0;
79 }
80
81 RTW_INFO("%s: GROUP_ID=0x%02x PARTIAL_AID=0x%04x\n",
82 __FUNCTION__, *g_id, *p_aid);
83 }
84
85 /*
86 * Parameters
87 * adapter struct _adapter*
88 * sta struct sta_info*
89 * sta_bf_cap beamforming capabe of sta
90 * sounding_dim Number of Sounding Dimensions
91 * comp_steering Compressed Steering Number of Beamformer Antennas Supported
92 */
_get_sta_beamform_cap(PADAPTER adapter,struct sta_info * sta,u8 * sta_bf_cap,u8 * sounding_dim,u8 * comp_steering)93 static void _get_sta_beamform_cap(PADAPTER adapter, struct sta_info *sta,
94 u8 *sta_bf_cap, u8 *sounding_dim, u8 *comp_steering)
95 {
96 struct beamforming_info *info;
97 struct mlme_priv *mlme;
98 struct ht_priv *ht;
99 u16 ht_bf_cap;
100 #ifdef CONFIG_80211AC_VHT
101 struct vht_priv *vht;
102 u16 vht_bf_cap;
103 #endif /* CONFIG_80211AC_VHT */
104
105
106 *sta_bf_cap = 0;
107 *sounding_dim = 0;
108 *comp_steering = 0;
109
110 info = GET_BEAMFORM_INFO(adapter);
111 ht = &adapter->mlmepriv.htpriv;
112 #ifdef CONFIG_80211AC_VHT
113 vht = &adapter->mlmepriv.vhtpriv;
114 #endif /* CONFIG_80211AC_VHT */
115 mlme = &adapter->mlmepriv;
116
117 if (is_supported_ht(sta->wireless_mode) == _FALSE)
118 goto get_bfcap_next;
119
120 /* HT */
121 if (check_fwstate(mlme, WIFI_AP_STATE)) {
122 /* Get peer clinet's BF cap: the cap. is intersected with associated AP.*/
123 ht_bf_cap = sta->htpriv.beamform_cap;
124 RTW_INFO("At AP state, peer sta's ht_bf_cap=0x%x\n", ht_bf_cap);
125
126 if (TEST_FLAG(ht_bf_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) {
127 info->beamforming_cap |= BEAMFORMER_CAP_HT_EXPLICIT;
128 *sta_bf_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;
129 *comp_steering = (ht_bf_cap & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4;
130 RTW_INFO("%s: we support BEAMFORMER_CAP_HT_EXPLICIT\n", __func__);
131 }
132 if (TEST_FLAG(ht_bf_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {
133 info->beamforming_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;
134 *sta_bf_cap |= BEAMFORMER_CAP_HT_EXPLICIT;
135 *sounding_dim = (ht_bf_cap & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6;
136 RTW_INFO("%s: we support BEAMFORMEE_CAP_HT_EXPLICIT\n", __func__);
137 }
138 } else {
139 /* Get adapter's BF Cap: the cap. is intersected with associated AP.*/
140 ht_bf_cap = ht->beamform_cap;
141 RTW_INFO("At non-AP state, adapter's ht_bf_cap=0x%x\n", ht_bf_cap);
142
143 if (TEST_FLAG(ht_bf_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) {
144 info->beamforming_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;
145 *sta_bf_cap |= BEAMFORMER_CAP_HT_EXPLICIT;
146 *sounding_dim = (ht_bf_cap & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6;
147 RTW_INFO("%s: we support BEAMFORMEE_CAP_HT_EXPLICIT\n", __func__);
148 }
149 if (TEST_FLAG(ht_bf_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {
150 info->beamforming_cap |= BEAMFORMER_CAP_HT_EXPLICIT;
151 *sta_bf_cap |= BEAMFORMEE_CAP_HT_EXPLICIT;
152 *comp_steering = (ht_bf_cap & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4;
153 RTW_INFO("%s: we support BEAMFORMER_CAP_HT_EXPLICIT\n", __func__);
154 }
155 }
156
157 get_bfcap_next:
158 #ifdef CONFIG_80211AC_VHT
159 if (is_supported_vht(sta->wireless_mode) == _FALSE)
160 return;
161
162 /* VHT */
163 if (check_fwstate(mlme, WIFI_AP_STATE)) {
164 /* Get peer clinet's BF cap: the cap. is intersected with associated AP.*/
165 vht_bf_cap = sta->vhtpriv.beamform_cap;
166 RTW_INFO("At AP state, peer sta's vht_bf_cap=0x%x\n", vht_bf_cap);
167
168 /* We are SU Beamformer because the STA is SU Beamformee */
169 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) {
170 info->beamforming_cap |= BEAMFORMER_CAP_VHT_SU;
171 *sta_bf_cap |= BEAMFORMEE_CAP_VHT_SU;
172 RTW_INFO("%s: we support BEAMFORMER_CAP_VHT_SU\n", __func__);
173
174 /* We are MU Beamformer because the STA is MU Beamformee */
175 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) {
176 info->beamforming_cap |= BEAMFORMER_CAP_VHT_MU;
177 *sta_bf_cap |= BEAMFORMEE_CAP_VHT_MU;
178 RTW_INFO("%s: we support BEAMFORMER_CAP_VHT_MU\n", __func__);
179 }
180
181 *comp_steering = (vht_bf_cap & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;
182 }
183 /* We are SU Beamformee because the STA is SU Beamformer */
184 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {
185 info->beamforming_cap |= BEAMFORMEE_CAP_VHT_SU;
186 *sta_bf_cap |= BEAMFORMER_CAP_VHT_SU;
187 RTW_INFO("%s: we support BEAMFORMEE_CAP_VHT_SU\n", __func__);
188
189 /* The STA is MU Beamformer, but we(AP) should not be MU Beamformee */
190 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {
191 RTW_WARN("%s: Associated STA should not be a MU BFer.\n", __func__);
192 }
193
194 *sounding_dim = (vht_bf_cap & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;
195 }
196 } else {
197 /* Get adapter's BF Cap: the cap. is intersected with associated AP.*/
198 vht_bf_cap = vht->beamform_cap;
199 RTW_INFO("At non-AP state, adapter's vht_bf_cap=0x%x\n", vht_bf_cap);
200
201 /* We are SU Beamformee */
202 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) {
203 info->beamforming_cap |= BEAMFORMEE_CAP_VHT_SU;
204 *sta_bf_cap |= BEAMFORMER_CAP_VHT_SU;
205 RTW_INFO("%s: we support BEAMFORMEE_CAP_VHT_SU\n", __func__);
206
207 /* We are MU Beamformee */
208 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) {
209 info->beamforming_cap |= BEAMFORMEE_CAP_VHT_MU;
210 *sta_bf_cap |= BEAMFORMER_CAP_VHT_MU;
211 RTW_INFO("%s: we support BEAMFORMEE_CAP_VHT_MU\n", __func__);
212 }
213
214 *sounding_dim = (vht_bf_cap & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;
215 }
216 /* We are SU Beamformer */
217 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {
218 info->beamforming_cap |= BEAMFORMER_CAP_VHT_SU;
219 *sta_bf_cap |= BEAMFORMEE_CAP_VHT_SU;
220 RTW_INFO("%s: we support BEAMFORMER_CAP_VHT_SU\n", __func__);
221
222 /* We are MU Beamformer, but client should not be a MU Beamformer */
223 if (TEST_FLAG(vht_bf_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {
224 RTW_WARN("%s: non-AP state should not support MU BFer.\n", __func__);
225 }
226
227 *comp_steering = (vht_bf_cap & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;
228 }
229 }
230 #endif /* CONFIG_80211AC_VHT */
231
232 }
233
_send_ht_ndpa_packet(PADAPTER adapter,u8 * ra,enum channel_width bw)234 static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, enum channel_width bw)
235 {
236 /* General */
237 struct xmit_priv *pxmitpriv;
238 struct mlme_ext_priv *pmlmeext;
239 struct mlme_ext_info *pmlmeinfo;
240 struct xmit_frame *pmgntframe;
241 /* Beamforming */
242 struct beamforming_info *info;
243 struct beamformee_entry *bfee;
244 struct ndpa_sta_info sta_info;
245 u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xE0, 0x4C};
246 /* MISC */
247 struct pkt_attrib *attrib;
248 struct rtw_ieee80211_hdr *pwlanhdr;
249 enum MGN_RATE txrate;
250 u8 *pframe;
251 u16 duration = 0;
252 u8 aSifsTime = 0;
253
254
255 RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));
256
257 pxmitpriv = &adapter->xmitpriv;
258 pmlmeext = &adapter->mlmeextpriv;
259 pmlmeinfo = &pmlmeext->mlmext_info;
260 bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra);
261 if (!bfee) {
262 RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__);
263 return _FALSE;
264 }
265
266 pmgntframe = alloc_mgtxmitframe(pxmitpriv);
267 if (!pmgntframe) {
268 RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
269 return _FALSE;
270 }
271
272 txrate = beamforming_get_htndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer);
273
274 /* update attribute */
275 attrib = &pmgntframe->attrib;
276 update_mgntframe_attrib(adapter, attrib);
277 /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
278 attrib->subtype = WIFI_ACTION_NOACK;
279 attrib->bwmode = bw;
280 /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
281 attrib->order = 1;
282 attrib->rate = (u8)txrate;
283 attrib->bf_pkt_type = 0;
284
285 _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
286 pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
287 pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
288
289 /* Frame control */
290 pwlanhdr->frame_ctl = 0;
291 set_frame_sub_type(pframe, attrib->subtype);
292 set_order_bit(pframe);
293
294 /* Duration */
295 if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
296 aSifsTime = 10;
297 else
298 aSifsTime = 16;
299 duration = 2 * aSifsTime + 40;
300 if (bw == CHANNEL_WIDTH_40)
301 duration += 87;
302 else
303 duration += 180;
304 set_duration(pframe, duration);
305
306 /* DA */
307 _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
308 /* SA */
309 _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
310 /* BSSID */
311 _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
312
313 /* HT control field */
314 SET_HT_CTRL_CSI_STEERING(pframe + 24, 3);
315 SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1);
316
317 /*
318 * Frame Body
319 * Category field: vender-specific value, 0x7F
320 * OUI: 0x00E04C
321 */
322 _rtw_memcpy(pframe + 28, ActionHdr, 4);
323
324 attrib->pktlen = 32;
325 attrib->last_txcmdsz = attrib->pktlen;
326
327 dump_mgntframe(adapter, pmgntframe);
328
329 return _TRUE;
330 }
331
_send_vht_ndpa_packet(PADAPTER adapter,u8 * ra,u16 aid,enum channel_width bw)332 static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, enum channel_width bw)
333 {
334 /* General */
335 struct xmit_priv *pxmitpriv;
336 struct mlme_ext_priv *pmlmeext;
337 struct xmit_frame *pmgntframe;
338 /* Beamforming */
339 struct beamforming_info *info;
340 struct beamformee_entry *bfee;
341 struct ndpa_sta_info sta_info;
342 /* MISC */
343 struct pkt_attrib *attrib;
344 struct rtw_ieee80211_hdr *pwlanhdr;
345 u8 *pframe;
346 enum MGN_RATE txrate;
347 u16 duration = 0;
348 u8 sequence = 0, aSifsTime = 0;
349
350
351 RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));
352
353 pxmitpriv = &adapter->xmitpriv;
354 pmlmeext = &adapter->mlmeextpriv;
355 info = GET_BEAMFORM_INFO(adapter);
356 bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra);
357 if (!bfee) {
358 RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__);
359 return _FALSE;
360 }
361
362 pmgntframe = alloc_mgtxmitframe(pxmitpriv);
363 if (!pmgntframe) {
364 RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
365 return _FALSE;
366 }
367
368 txrate = beamforming_get_vht_ndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer);
369
370 /* update attribute */
371 attrib = &pmgntframe->attrib;
372 update_mgntframe_attrib(adapter, attrib);
373 /*pattrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
374 attrib->subtype = WIFI_NDPA;
375 attrib->bwmode = bw;
376 /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
377 attrib->rate = (u8)txrate;
378 attrib->bf_pkt_type = 0;
379
380 _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);
381 pframe = pmgntframe->buf_addr + TXDESC_OFFSET;
382 pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
383
384 /* Frame control */
385 pwlanhdr->frame_ctl = 0;
386 set_frame_sub_type(pframe, attrib->subtype);
387
388 /* Duration */
389 if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
390 aSifsTime = 16;
391 else
392 aSifsTime = 10;
393 duration = 2 * aSifsTime + 44;
394 if (bw == CHANNEL_WIDTH_80)
395 duration += 40;
396 else if (bw == CHANNEL_WIDTH_40)
397 duration += 87;
398 else
399 duration += 180;
400 set_duration(pframe, duration);
401
402 /* RA */
403 _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
404
405 /* TA */
406 _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
407
408 /* Sounding Sequence, bit0~1 is reserved */
409 sequence = info->sounding_sequence << 2;
410 if (info->sounding_sequence >= 0x3f)
411 info->sounding_sequence = 0;
412 else
413 info->sounding_sequence++;
414 _rtw_memcpy(pframe + 16, &sequence, 1);
415
416 /* STA Info */
417 /*
418 * "AID12" Equal to 0 if the STA is an AP, mesh STA or
419 * STA that is a member of an IBSS
420 */
421 if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _FALSE)
422 aid = 0;
423 sta_info.aid = aid;
424 /* "Feedback Type" set to 0 for SU */
425 sta_info.feedback_type = 0;
426 /* "Nc Index" reserved if the Feedback Type field indicates SU */
427 sta_info.nc_index = 0;
428 _rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2);
429
430 attrib->pktlen = 19;
431 attrib->last_txcmdsz = attrib->pktlen;
432
433 dump_mgntframe(adapter, pmgntframe);
434
435 return _TRUE;
436 }
437
_send_vht_mu_ndpa_packet(PADAPTER adapter,enum channel_width bw)438 static u8 _send_vht_mu_ndpa_packet(PADAPTER adapter, enum channel_width bw)
439 {
440 /* General */
441 struct xmit_priv *pxmitpriv;
442 struct mlme_ext_priv *pmlmeext;
443 struct xmit_frame *pmgntframe;
444 /* Beamforming */
445 struct beamforming_info *info;
446 struct sounding_info *sounding;
447 struct beamformee_entry *bfee;
448 struct ndpa_sta_info sta_info;
449 /* MISC */
450 struct pkt_attrib *attrib;
451 struct rtw_ieee80211_hdr *pwlanhdr;
452 enum MGN_RATE txrate;
453 u8 *pframe;
454 u8 *ra = NULL;
455 u16 duration = 0;
456 u8 sequence = 0, aSifsTime = 0;
457 u8 i;
458
459
460 RTW_INFO("+%s\n", __FUNCTION__);
461
462 pxmitpriv = &adapter->xmitpriv;
463 pmlmeext = &adapter->mlmeextpriv;
464 info = GET_BEAMFORM_INFO(adapter);
465 sounding = &info->sounding_info;
466
467 txrate = MGN_VHT2SS_MCS0;
468
469 /*
470 * Fill the first MU BFee entry (STA1) MAC addr to destination address then
471 * HW will change A1 to broadcast addr.
472 * 2015.05.28. Suggested by SD1 Chunchu.
473 */
474 bfee = &info->bfee_entry[sounding->mu_sounding_list[0]];
475 ra = bfee->mac_addr;
476
477 pmgntframe = alloc_mgtxmitframe(pxmitpriv);
478 if (!pmgntframe) {
479 RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
480 return _FALSE;
481 }
482
483 /* update attribute */
484 attrib = &pmgntframe->attrib;
485 update_mgntframe_attrib(adapter, attrib);
486 /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
487 attrib->subtype = WIFI_NDPA;
488 attrib->bwmode = bw;
489 /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
490 attrib->rate = (u8)txrate;
491 /* Set TxBFPktType of Tx desc to unicast type if there is only one MU STA for HW design */
492 if (info->sounding_info.candidate_mu_bfee_cnt > 1)
493 attrib->bf_pkt_type = 1;
494 else
495 attrib->bf_pkt_type = 0;
496
497 _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);
498 pframe = pmgntframe->buf_addr + TXDESC_OFFSET;
499 pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
500
501 /* Frame control */
502 pwlanhdr->frame_ctl = 0;
503 set_frame_sub_type(pframe, attrib->subtype);
504
505 /* Duration */
506 if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
507 aSifsTime = 16;
508 else
509 aSifsTime = 10;
510 duration = 2 * aSifsTime + 44;
511 if (bw == CHANNEL_WIDTH_80)
512 duration += 40;
513 else if (bw == CHANNEL_WIDTH_40)
514 duration += 87;
515 else
516 duration += 180;
517 set_duration(pframe, duration);
518
519 /* RA */
520 _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
521
522 /* TA */
523 _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
524
525 /* Sounding Sequence, bit0~1 is reserved */
526 sequence = info->sounding_sequence << 2;
527 if (info->sounding_sequence >= 0x3f)
528 info->sounding_sequence = 0;
529 else
530 info->sounding_sequence++;
531 _rtw_memcpy(pframe + 16, &sequence, 1);
532
533 attrib->pktlen = 17;
534
535 /*
536 * Construct STA info. for multiple STAs
537 * STA Info1, ..., STA Info n
538 */
539 for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) {
540 bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];
541 sta_info.aid = bfee->aid;
542 sta_info.feedback_type = 1; /* 1'b1: MU */
543 sta_info.nc_index = 0;
544 _rtw_memcpy(pframe + attrib->pktlen, (u8 *)&sta_info, 2);
545 attrib->pktlen += 2;
546 }
547
548 attrib->last_txcmdsz = attrib->pktlen;
549
550 dump_mgntframe(adapter, pmgntframe);
551
552 return _TRUE;
553 }
554
_send_bf_report_poll(PADAPTER adapter,u8 * ra,u8 bFinalPoll)555 static u8 _send_bf_report_poll(PADAPTER adapter, u8 *ra, u8 bFinalPoll)
556 {
557 /* General */
558 struct xmit_priv *pxmitpriv;
559 struct xmit_frame *pmgntframe;
560 /* MISC */
561 struct pkt_attrib *attrib;
562 struct rtw_ieee80211_hdr *pwlanhdr;
563 u8 *pframe;
564
565
566 RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra));
567
568 pxmitpriv = &adapter->xmitpriv;
569
570 pmgntframe = alloc_mgtxmitframe(pxmitpriv);
571 if (!pmgntframe) {
572 RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__);
573 return _FALSE;
574 }
575
576 /* update attribute */
577 attrib = &pmgntframe->attrib;
578 update_mgntframe_attrib(adapter, attrib);
579 /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */
580 attrib->subtype = WIFI_BF_REPORT_POLL;
581 attrib->bwmode = CHANNEL_WIDTH_20;
582 /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */
583 attrib->rate = MGN_6M;
584 if (bFinalPoll)
585 attrib->bf_pkt_type = 3;
586 else
587 attrib->bf_pkt_type = 2;
588
589 _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET);
590 pframe = pmgntframe->buf_addr + TXDESC_OFFSET;
591 pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
592
593 /* Frame control */
594 pwlanhdr->frame_ctl = 0;
595 set_frame_sub_type(pframe, attrib->subtype);
596
597 /* Duration */
598 set_duration(pframe, 100);
599
600 /* RA */
601 _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
602
603 /* TA */
604 _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
605
606 /* Feedback Segment Retransmission Bitmap */
607 pframe[16] = 0xFF;
608
609 attrib->pktlen = 17;
610 attrib->last_txcmdsz = attrib->pktlen;
611
612 dump_mgntframe(adapter, pmgntframe);
613
614 return _TRUE;
615 }
616
_sounding_update_min_period(PADAPTER adapter,u16 period,u8 leave)617 static void _sounding_update_min_period(PADAPTER adapter, u16 period, u8 leave)
618 {
619 struct beamforming_info *info;
620 struct beamformee_entry *bfee;
621 u8 i = 0;
622 u16 min_val = 0xFFFF;
623
624
625 info = GET_BEAMFORM_INFO(adapter);
626
627 if (_TRUE == leave) {
628 /*
629 * When a BFee left,
630 * we need to find the latest min sounding period
631 * from the remaining BFees
632 */
633 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
634 bfee = &info->bfee_entry[i];
635 if ((bfee->used == _TRUE)
636 && (bfee->sound_period < min_val))
637 min_val = bfee->sound_period;
638 }
639
640 if (min_val == 0xFFFF)
641 info->sounding_info.min_sounding_period = 0;
642 else
643 info->sounding_info.min_sounding_period = min_val;
644 } else {
645 if ((info->sounding_info.min_sounding_period == 0)
646 || (period < info->sounding_info.min_sounding_period))
647 info->sounding_info.min_sounding_period = period;
648 }
649 }
650
_sounding_init(struct sounding_info * sounding)651 static void _sounding_init(struct sounding_info *sounding)
652 {
653 _rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU);
654 _rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU);
655 sounding->state = SOUNDING_STATE_NONE;
656 sounding->su_bfee_curidx = 0xFF;
657 sounding->candidate_mu_bfee_cnt = 0;
658 sounding->min_sounding_period = 0;
659 sounding->sound_remain_cnt_per_period = 0;
660 }
661
_sounding_reset_vars(PADAPTER adapter)662 static void _sounding_reset_vars(PADAPTER adapter)
663 {
664 struct beamforming_info *info;
665 struct sounding_info *sounding;
666 u8 idx;
667
668
669 info = GET_BEAMFORM_INFO(adapter);
670 sounding = &info->sounding_info;
671
672 _rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU);
673 _rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU);
674 sounding->su_bfee_curidx = 0xFF;
675 sounding->candidate_mu_bfee_cnt = 0;
676
677 /* Clear bSound flag for the new period */
678 for (idx = 0; idx < MAX_BEAMFORMEE_ENTRY_NUM; idx++) {
679 if ((info->bfee_entry[idx].used == _TRUE)
680 && (info->bfee_entry[idx].sounding == _TRUE)) {
681 info->bfee_entry[idx].sounding = _FALSE;
682 info->bfee_entry[idx].bCandidateSoundingPeer = _FALSE;
683 }
684 }
685 }
686
687 /*
688 * Return
689 * 0 Prepare sounding list OK
690 * -1 Fail to prepare sounding list, because no beamformee need to souding
691 * -2 Fail to prepare sounding list, because beamformee state not ready
692 *
693 */
_sounding_get_list(PADAPTER adapter)694 static int _sounding_get_list(PADAPTER adapter)
695 {
696 struct beamforming_info *info;
697 struct sounding_info *sounding;
698 struct beamformee_entry *bfee;
699 u8 i, mu_idx = 0, su_idx = 0, not_ready = 0;
700 int ret = 0;
701
702
703 info = GET_BEAMFORM_INFO(adapter);
704 sounding = &info->sounding_info;
705
706 /* Add MU BFee list first because MU priority is higher than SU */
707 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
708 bfee = &info->bfee_entry[i];
709 if (bfee->used == _FALSE)
710 continue;
711
712 if (bfee->state != BEAMFORM_ENTRY_HW_STATE_ADDED) {
713 RTW_ERR("%s: Invalid BFee idx(%d) Hw state=%d\n", __FUNCTION__, i, bfee->state);
714 not_ready++;
715 continue;
716 }
717
718 /*
719 * Decrease BFee's SoundCnt per period
720 * If the remain count is 0,
721 * then it can be sounded at this time
722 */
723 if (bfee->SoundCnt) {
724 bfee->SoundCnt--;
725 if (bfee->SoundCnt)
726 continue;
727 }
728
729 /*
730 * <tynli_Note>
731 * If the STA supports MU BFee capability then we add it to MUSoundingList directly
732 * because we can only sound one STA by unicast NDPA with MU cap enabled to get correct channel info.
733 * Suggested by BB team Luke Lee. 2015.11.25.
734 */
735 if (bfee->cap & BEAMFORMEE_CAP_VHT_MU) {
736 /* MU BFee */
737 if (mu_idx >= MAX_NUM_BEAMFORMEE_MU) {
738 RTW_ERR("%s: Too much MU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_MU);
739 continue;
740 }
741
742 if (bfee->bApplySounding == _TRUE) {
743 bfee->bCandidateSoundingPeer = _TRUE;
744 bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period);
745 sounding->mu_sounding_list[mu_idx] = i;
746 mu_idx++;
747 }
748 } else if (bfee->cap & (BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {
749 /* SU BFee (HT/VHT) */
750 if (su_idx >= MAX_NUM_BEAMFORMEE_SU) {
751 RTW_ERR("%s: Too much SU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_SU);
752 continue;
753 }
754
755 if (bfee->bDeleteSounding == _TRUE) {
756 sounding->su_sounding_list[su_idx] = i;
757 su_idx++;
758 } else if ((bfee->bApplySounding == _TRUE)
759 && (bfee->bSuspendSUCap == _FALSE)) {
760 bfee->bCandidateSoundingPeer = _TRUE;
761 bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period);
762 sounding->su_sounding_list[su_idx] = i;
763 su_idx++;
764 }
765 }
766 }
767
768 sounding->candidate_mu_bfee_cnt = mu_idx;
769
770 if (su_idx + mu_idx == 0) {
771 ret = -1;
772 if (not_ready)
773 ret = -2;
774 }
775
776 RTW_INFO("-%s: There are %d SU and %d MU BFees in this sounding period\n", __FUNCTION__, su_idx, mu_idx);
777
778 return ret;
779 }
780
_sounding_handler(PADAPTER adapter)781 static void _sounding_handler(PADAPTER adapter)
782 {
783 struct beamforming_info *info;
784 struct sounding_info *sounding;
785 struct beamformee_entry *bfee;
786 u8 su_idx, i;
787 u32 timeout_period = 0;
788 u8 set_timer = _FALSE;
789 int ret = 0;
790 static u16 wait_cnt = 0;
791
792
793 info = GET_BEAMFORM_INFO(adapter);
794 sounding = &info->sounding_info;
795
796 RTW_DBG("+%s: state=%d\n", __FUNCTION__, sounding->state);
797 if ((sounding->state != SOUNDING_STATE_INIT)
798 && (sounding->state != SOUNDING_STATE_SU_SOUNDDOWN)
799 && (sounding->state != SOUNDING_STATE_MU_SOUNDDOWN)
800 && (sounding->state != SOUNDING_STATE_SOUNDING_TIMEOUT)) {
801 RTW_WARN("%s: Invalid State(%d) and return!\n", __FUNCTION__, sounding->state);
802 return;
803 }
804
805 if (sounding->state == SOUNDING_STATE_INIT) {
806 RTW_INFO("%s: Sounding start\n", __FUNCTION__);
807
808 /* Init Var */
809 _sounding_reset_vars(adapter);
810
811 /* Get the sounding list of this sounding period */
812 ret = _sounding_get_list(adapter);
813 if (ret == -1) {
814 wait_cnt = 0;
815 sounding->state = SOUNDING_STATE_NONE;
816 RTW_ERR("%s: No BFees found, set to SOUNDING_STATE_NONE\n", __FUNCTION__);
817 info->sounding_running--;
818 return;
819 }
820 if (ret == -2) {
821 RTW_WARN("%s: Temporarily cann't find BFee to sounding\n", __FUNCTION__);
822 if (wait_cnt < 5) {
823 wait_cnt++;
824 } else {
825 wait_cnt = 0;
826 sounding->state = SOUNDING_STATE_NONE;
827 RTW_ERR("%s: Wait changing state timeout!! Set to SOUNDING_STATE_NONE\n", __FUNCTION__);
828 }
829 info->sounding_running--;
830 return;
831 }
832 if (ret != 0) {
833 wait_cnt = 0;
834 RTW_ERR("%s: Unkown state(%d)!\n", __FUNCTION__, ret);
835 info->sounding_running--;
836 return;
837
838 }
839
840 wait_cnt = 0;
841
842 if (check_fwstate(&adapter->mlmepriv, WIFI_UNDER_SURVEY) == _TRUE) {
843 RTW_INFO("%s: Sounding abort! scanning APs...\n", __FUNCTION__);
844 info->sounding_running--;
845 return;
846 }
847
848 rtw_ps_deny(adapter, PS_DENY_BEAMFORMING);
849 LeaveAllPowerSaveModeDirect(adapter);
850 }
851
852 /* Get non-sound SU BFee index */
853 for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) {
854 su_idx = sounding->su_sounding_list[i];
855 if (su_idx >= MAX_BEAMFORMEE_ENTRY_NUM)
856 continue;
857 bfee = &info->bfee_entry[su_idx];
858 if (_FALSE == bfee->sounding)
859 break;
860 }
861 if (i < MAX_NUM_BEAMFORMEE_SU) {
862 sounding->su_bfee_curidx = su_idx;
863 /* Set to sounding start state */
864 sounding->state = SOUNDING_STATE_SU_START;
865 RTW_DBG("%s: Set to SOUNDING_STATE_SU_START\n", __FUNCTION__);
866
867 bfee->sounding = _TRUE;
868 /* Reset sounding timeout flag for the new sounding */
869 bfee->bSoundingTimeout = _FALSE;
870
871 if (_TRUE == bfee->bDeleteSounding) {
872 u8 res = _FALSE;
873 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 0);
874 return;
875 }
876
877 /* Start SU sounding */
878 if (bfee->cap & BEAMFORMEE_CAP_VHT_SU)
879 _send_vht_ndpa_packet(adapter, bfee->mac_addr, bfee->aid, bfee->sound_bw);
880 else if (bfee->cap & BEAMFORMEE_CAP_HT_EXPLICIT)
881 _send_ht_ndpa_packet(adapter, bfee->mac_addr, bfee->sound_bw);
882
883 /* Set sounding timeout timer */
884 _set_timer(&info->sounding_timeout_timer, SU_SOUNDING_TIMEOUT);
885 return;
886 }
887
888 if (sounding->candidate_mu_bfee_cnt > 0) {
889 /*
890 * If there is no SU BFee then find MU BFee and perform MU sounding
891 *
892 * <tynli_note> Need to check the MU starting condition. 2015.12.15.
893 */
894 sounding->state = SOUNDING_STATE_MU_START;
895 RTW_DBG("%s: Set to SOUNDING_STATE_MU_START\n", __FUNCTION__);
896
897 /* Update MU BFee info */
898 for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) {
899 bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];
900 bfee->sounding = _TRUE;
901 }
902
903 /* Send MU NDPA */
904 bfee = &info->bfee_entry[sounding->mu_sounding_list[0]];
905 _send_vht_mu_ndpa_packet(adapter, bfee->sound_bw);
906
907 /* Send BF report poll if more than 1 MU STA */
908 for (i = 1; i < sounding->candidate_mu_bfee_cnt; i++) {
909 bfee = &info->bfee_entry[sounding->mu_sounding_list[i]];
910
911 if (i == (sounding->candidate_mu_bfee_cnt - 1))/* The last STA*/
912 _send_bf_report_poll(adapter, bfee->mac_addr, _TRUE);
913 else
914 _send_bf_report_poll(adapter, bfee->mac_addr, _FALSE);
915 }
916
917 sounding->candidate_mu_bfee_cnt = 0;
918
919 /* Set sounding timeout timer */
920 _set_timer(&info->sounding_timeout_timer, MU_SOUNDING_TIMEOUT);
921 return;
922 }
923
924 info->sounding_running--;
925 sounding->state = SOUNDING_STATE_INIT;
926 RTW_INFO("%s: Sounding finished!\n", __FUNCTION__);
927 rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING);
928 }
929
_sounding_force_stop(PADAPTER adapter)930 static void _sounding_force_stop(PADAPTER adapter)
931 {
932 struct beamforming_info *info;
933 struct sounding_info *sounding;
934
935 info = GET_BEAMFORM_INFO(adapter);
936 sounding = &info->sounding_info;
937
938 if ((sounding->state == SOUNDING_STATE_SU_START)
939 || (sounding->state == SOUNDING_STATE_MU_START)) {
940 u8 res = _FALSE;
941 _cancel_timer_ex(&info->sounding_timeout_timer);
942 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1);
943 return;
944 }
945
946 info->sounding_running--;
947 sounding->state = SOUNDING_STATE_INIT;
948 RTW_INFO("%s: Sounding finished!\n", __FUNCTION__);
949 rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING);
950 }
951
_sounding_timer_handler(void * FunctionContext)952 static void _sounding_timer_handler(void *FunctionContext)
953 {
954 PADAPTER adapter;
955 struct beamforming_info *info;
956 struct sounding_info *sounding;
957 static u8 delay = 0;
958
959
960 RTW_DBG("+%s\n", __FUNCTION__);
961
962 adapter = (PADAPTER)FunctionContext;
963 info = GET_BEAMFORM_INFO(adapter);
964 sounding = &info->sounding_info;
965
966 if (SOUNDING_STATE_NONE == sounding->state) {
967 RTW_INFO("%s: Stop!\n", __FUNCTION__);
968 if (info->sounding_running)
969 RTW_WARN("%s: souding_running=%d when thread stop!\n",
970 __FUNCTION__, info->sounding_running);
971 return;
972 }
973
974 _set_timer(&info->sounding_timer, sounding->min_sounding_period);
975
976 if (!info->sounding_running) {
977 if (SOUNDING_STATE_INIT != sounding->state) {
978 RTW_WARN("%s: state(%d) != SOUNDING_STATE_INIT!!\n", __FUNCTION__, sounding->state);
979 sounding->state = SOUNDING_STATE_INIT;
980 }
981 delay = 0;
982 info->sounding_running++;
983 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1);
984 } else {
985 if (delay != 0xFF)
986 delay++;
987 RTW_WARN("%s: souding is still processing...(state:%d, running:%d, delay:%d)\n",
988 __FUNCTION__, sounding->state, info->sounding_running, delay);
989 if (delay > 3) {
990 RTW_WARN("%s: Stop sounding!!\n", __FUNCTION__);
991 _sounding_force_stop(adapter);
992 }
993 }
994 }
995
_sounding_timeout_timer_handler(void * FunctionContext)996 static void _sounding_timeout_timer_handler(void *FunctionContext)
997 {
998 PADAPTER adapter;
999 struct beamforming_info *info;
1000 struct sounding_info *sounding;
1001 struct beamformee_entry *bfee;
1002
1003
1004 RTW_WARN("+%s\n", __FUNCTION__);
1005
1006 adapter = (PADAPTER)FunctionContext;
1007 info = GET_BEAMFORM_INFO(adapter);
1008 sounding = &info->sounding_info;
1009
1010 if (SOUNDING_STATE_SU_START == sounding->state) {
1011 sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT;
1012 RTW_ERR("%s: Set to SU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__);
1013 /* SU BFee */
1014 bfee = &info->bfee_entry[sounding->su_bfee_curidx];
1015 bfee->bSoundingTimeout = _TRUE;
1016 RTW_WARN("%s: The BFee entry[%d] is Sounding Timeout!\n", __FUNCTION__, sounding->su_bfee_curidx);
1017 } else if (SOUNDING_STATE_MU_START == sounding->state) {
1018 sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT;
1019 RTW_ERR("%s: Set to MU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__);
1020 } else {
1021 RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state);
1022 return;
1023 }
1024
1025 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1);
1026 }
1027
_bfer_get_free_entry(PADAPTER adapter)1028 static struct beamformer_entry *_bfer_get_free_entry(PADAPTER adapter)
1029 {
1030 u8 i = 0;
1031 struct beamforming_info *info;
1032 struct beamformer_entry *bfer;
1033
1034
1035 info = GET_BEAMFORM_INFO(adapter);
1036
1037 for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {
1038 bfer = &info->bfer_entry[i];
1039 if (bfer->used == _FALSE)
1040 return bfer;
1041 }
1042
1043 return NULL;
1044 }
1045
_bfer_get_entry_by_addr(PADAPTER adapter,u8 * ra)1046 static struct beamformer_entry *_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra)
1047 {
1048 u8 i = 0;
1049 struct beamforming_info *info;
1050 struct beamformer_entry *bfer;
1051
1052
1053 info = GET_BEAMFORM_INFO(adapter);
1054
1055 for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {
1056 bfer = &info->bfer_entry[i];
1057 if (bfer->used == _FALSE)
1058 continue;
1059 if (_rtw_memcmp(ra, bfer->mac_addr, ETH_ALEN) == _TRUE)
1060 return bfer;
1061 }
1062
1063 return NULL;
1064 }
1065
_bfer_add_entry(PADAPTER adapter,struct sta_info * sta,u8 bf_cap,u8 sounding_dim,u8 comp_steering)1066 static struct beamformer_entry *_bfer_add_entry(PADAPTER adapter,
1067 struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering)
1068 {
1069 struct mlme_priv *mlme;
1070 struct beamforming_info *info;
1071 struct beamformer_entry *bfer;
1072 u8 *bssid;
1073 u16 val16;
1074 u8 i;
1075
1076
1077 mlme = &adapter->mlmepriv;
1078 info = GET_BEAMFORM_INFO(adapter);
1079
1080 bfer = _bfer_get_entry_by_addr(adapter, sta->cmn.mac_addr);
1081 if (!bfer) {
1082 bfer = _bfer_get_free_entry(adapter);
1083 if (!bfer)
1084 return NULL;
1085 }
1086
1087 bfer->used = _TRUE;
1088 _get_txvector_parameter(adapter, sta, &bfer->g_id, &bfer->p_aid);
1089 _rtw_memcpy(bfer->mac_addr, sta->cmn.mac_addr, ETH_ALEN);
1090 bfer->cap = bf_cap;
1091 bfer->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT;
1092 bfer->NumofSoundingDim = sounding_dim;
1093
1094 if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_MU)) {
1095 info->beamformer_mu_cnt += 1;
1096 bfer->aid = sta->cmn.aid;
1097 } else if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) {
1098 info->beamformer_su_cnt += 1;
1099
1100 /* Record HW idx info */
1101 for (i = 0; i < MAX_NUM_BEAMFORMER_SU; i++) {
1102 if ((info->beamformer_su_reg_maping & BIT(i)) == 0) {
1103 info->beamformer_su_reg_maping |= BIT(i);
1104 bfer->su_reg_index = i;
1105 break;
1106 }
1107 }
1108 RTW_INFO("%s: Add BFer entry beamformer_su_reg_maping=%#x, su_reg_index=%d\n",
1109 __FUNCTION__, info->beamformer_su_reg_maping, bfer->su_reg_index);
1110 }
1111
1112 return bfer;
1113 }
1114
_bfer_remove_entry(PADAPTER adapter,struct beamformer_entry * entry)1115 static void _bfer_remove_entry(PADAPTER adapter, struct beamformer_entry *entry)
1116 {
1117 struct beamforming_info *info;
1118
1119
1120 info = GET_BEAMFORM_INFO(adapter);
1121
1122 entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT;
1123
1124 if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_MU)) {
1125 info->beamformer_mu_cnt -= 1;
1126 _rtw_memset(entry->gid_valid, 0, 8);
1127 _rtw_memset(entry->user_position, 0, 16);
1128 } else if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) {
1129 info->beamformer_su_cnt -= 1;
1130 }
1131
1132 if (info->beamformer_mu_cnt == 0)
1133 info->beamforming_cap &= ~BEAMFORMEE_CAP_VHT_MU;
1134 if (info->beamformer_su_cnt == 0)
1135 info->beamforming_cap &= ~(BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT);
1136 }
1137
_bfer_set_entry_gid(PADAPTER adapter,u8 * addr,u8 * gid,u8 * position)1138 static u8 _bfer_set_entry_gid(PADAPTER adapter, u8 *addr, u8 *gid, u8 *position)
1139 {
1140 struct beamformer_entry bfer;
1141
1142 memset(&bfer, 0, sizeof(bfer));
1143 memcpy(bfer.mac_addr, addr, ETH_ALEN);
1144
1145 /* Parsing Membership Status Array */
1146 memcpy(bfer.gid_valid, gid, 8);
1147
1148 /* Parsing User Position Array */
1149 memcpy(bfer.user_position, position, 16);
1150
1151 /* Config HW GID table */
1152 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_GID_TABLE, (u8 *) &bfer,
1153 sizeof(bfer), 1);
1154
1155 return _SUCCESS;
1156 }
1157
_bfee_get_free_entry(PADAPTER adapter)1158 static struct beamformee_entry *_bfee_get_free_entry(PADAPTER adapter)
1159 {
1160 u8 i = 0;
1161 struct beamforming_info *info;
1162 struct beamformee_entry *bfee;
1163
1164
1165 info = GET_BEAMFORM_INFO(adapter);
1166
1167 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
1168 bfee = &info->bfee_entry[i];
1169 if (bfee->used == _FALSE)
1170 return bfee;
1171 }
1172
1173 return NULL;
1174 }
1175
_bfee_get_entry_by_addr(PADAPTER adapter,u8 * ra)1176 static struct beamformee_entry *_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra)
1177 {
1178 u8 i = 0;
1179 struct beamforming_info *info;
1180 struct beamformee_entry *bfee;
1181
1182
1183 info = GET_BEAMFORM_INFO(adapter);
1184
1185 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
1186 bfee = &info->bfee_entry[i];
1187 if (bfee->used == _FALSE)
1188 continue;
1189 if (_rtw_memcmp(ra, bfee->mac_addr, ETH_ALEN) == _TRUE)
1190 return bfee;
1191 }
1192
1193 return NULL;
1194 }
1195
_bfee_get_first_su_entry_idx(PADAPTER adapter,struct beamformee_entry * ignore)1196 static u8 _bfee_get_first_su_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore)
1197 {
1198 struct beamforming_info *info;
1199 struct beamformee_entry *bfee;
1200 u8 i;
1201
1202
1203 info = GET_BEAMFORM_INFO(adapter);
1204
1205 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
1206 bfee = &info->bfee_entry[i];
1207 if (ignore && (bfee == ignore))
1208 continue;
1209 if (bfee->used == _FALSE)
1210 continue;
1211 if ((!TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU))
1212 && TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT))
1213 return i;
1214 }
1215
1216 return 0xFF;
1217 }
1218
1219 /*
1220 * Description:
1221 * Get the first entry index of MU Beamformee.
1222 *
1223 * Return Value:
1224 * Index of the first MU sta, or 0xFF for invalid index.
1225 *
1226 * 2015.05.25. Created by tynli.
1227 *
1228 */
_bfee_get_first_mu_entry_idx(PADAPTER adapter,struct beamformee_entry * ignore)1229 static u8 _bfee_get_first_mu_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore)
1230 {
1231 struct beamforming_info *info;
1232 struct beamformee_entry *bfee;
1233 u8 i;
1234
1235
1236 info = GET_BEAMFORM_INFO(adapter);
1237
1238 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
1239 bfee = &info->bfee_entry[i];
1240 if (ignore && (bfee == ignore))
1241 continue;
1242 if (bfee->used == _FALSE)
1243 continue;
1244 if (TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU))
1245 return i;
1246 }
1247
1248 return 0xFF;
1249 }
1250
_bfee_add_entry(PADAPTER adapter,struct sta_info * sta,u8 bf_cap,u8 sounding_dim,u8 comp_steering)1251 static struct beamformee_entry *_bfee_add_entry(PADAPTER adapter,
1252 struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering)
1253 {
1254 struct mlme_priv *mlme;
1255 struct beamforming_info *info;
1256 struct beamformee_entry *bfee;
1257 u8 *bssid;
1258 u16 val16;
1259 u8 i;
1260
1261
1262 mlme = &adapter->mlmepriv;
1263 info = GET_BEAMFORM_INFO(adapter);
1264
1265 bfee = _bfee_get_entry_by_addr(adapter, sta->cmn.mac_addr);
1266 if (!bfee) {
1267 bfee = _bfee_get_free_entry(adapter);
1268 if (!bfee)
1269 return NULL;
1270 }
1271
1272 bfee->used = _TRUE;
1273 bfee->aid = sta->cmn.aid;
1274 bfee->mac_id = sta->cmn.mac_id;
1275 bfee->sound_bw = sta->cmn.bw_mode;
1276
1277 _get_txvector_parameter(adapter, sta, &bfee->g_id, &bfee->p_aid);
1278 sta->cmn.bf_info.g_id = bfee->g_id;
1279 sta->cmn.bf_info.p_aid = bfee->p_aid;
1280
1281 _rtw_memcpy(bfee->mac_addr, sta->cmn.mac_addr, ETH_ALEN);
1282 bfee->txbf = _FALSE;
1283 bfee->sounding = _FALSE;
1284 bfee->sound_period = 40;
1285 _sounding_update_min_period(adapter, bfee->sound_period, _FALSE);
1286 bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, info->sounding_info.min_sounding_period);
1287 bfee->cap = bf_cap;
1288 bfee->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT;
1289
1290 bfee->bCandidateSoundingPeer = _FALSE;
1291 bfee->bSoundingTimeout = _FALSE;
1292 bfee->bDeleteSounding = _FALSE;
1293 bfee->bApplySounding = _TRUE;
1294
1295 bfee->tx_timestamp = 0;
1296 bfee->tx_bytes = 0;
1297
1298 bfee->LogStatusFailCnt = 0;
1299 bfee->NumofSoundingDim = sounding_dim;
1300 bfee->comp_steering_num_of_bfer = comp_steering;
1301 bfee->bSuspendSUCap = _FALSE;
1302
1303 if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_MU)) {
1304 info->beamformee_mu_cnt += 1;
1305 info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, NULL);
1306
1307 if (_TRUE == info->bEnableSUTxBFWorkAround) {
1308 /* When the first MU BFee added, discard SU BFee bfee's capability */
1309 if ((info->beamformee_mu_cnt == 1) && (info->beamformee_su_cnt > 0)) {
1310 if (info->TargetSUBFee) {
1311 info->TargetSUBFee->bSuspendSUCap = _TRUE;
1312 info->TargetSUBFee->bDeleteSounding = _TRUE;
1313 } else {
1314 RTW_ERR("%s: UNEXPECTED!! info->TargetSUBFee is NULL!", __FUNCTION__);
1315 }
1316 info->TargetSUBFee = NULL;
1317 _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
1318 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0);
1319 }
1320 }
1321
1322 /* Record HW idx info */
1323 for (i = 0; i < MAX_NUM_BEAMFORMEE_MU; i++) {
1324 if ((info->beamformee_mu_reg_maping & BIT(i)) == 0) {
1325 info->beamformee_mu_reg_maping |= BIT(i);
1326 bfee->mu_reg_index = i;
1327 break;
1328 }
1329 }
1330 RTW_INFO("%s: Add BFee entry beamformee_mu_reg_maping=%#x, mu_reg_index=%d\n",
1331 __FUNCTION__, info->beamformee_mu_reg_maping, bfee->mu_reg_index);
1332
1333 } else if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {
1334 info->beamformee_su_cnt += 1;
1335
1336 if (_TRUE == info->bEnableSUTxBFWorkAround) {
1337 /* Record the first SU BFee index. We only allow the first SU BFee to be sound */
1338 if ((info->beamformee_su_cnt == 1) && (info->beamformee_mu_cnt == 0)) {
1339 info->TargetSUBFee = bfee;
1340 _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
1341 bfee->bSuspendSUCap = _FALSE;
1342 } else {
1343 bfee->bSuspendSUCap = _TRUE;
1344 }
1345 }
1346
1347 /* Record HW idx info */
1348 for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) {
1349 if ((info->beamformee_su_reg_maping & BIT(i)) == 0) {
1350 info->beamformee_su_reg_maping |= BIT(i);
1351 bfee->su_reg_index = i;
1352 break;
1353 }
1354 }
1355 RTW_INFO("%s: Add BFee entry beamformee_su_reg_maping=%#x, su_reg_index=%d\n",
1356 __FUNCTION__, info->beamformee_su_reg_maping, bfee->su_reg_index);
1357 }
1358
1359 return bfee;
1360 }
1361
_bfee_remove_entry(PADAPTER adapter,struct beamformee_entry * entry)1362 static void _bfee_remove_entry(PADAPTER adapter, struct beamformee_entry *entry)
1363 {
1364 struct beamforming_info *info;
1365 u8 idx;
1366
1367
1368 info = GET_BEAMFORM_INFO(adapter);
1369
1370 entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT;
1371
1372 if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_MU)) {
1373 info->beamformee_mu_cnt -= 1;
1374 info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, entry);
1375
1376 if (_TRUE == info->bEnableSUTxBFWorkAround) {
1377 if ((info->beamformee_mu_cnt == 0) && (info->beamformee_su_cnt > 0)) {
1378 idx = _bfee_get_first_su_entry_idx(adapter, NULL);
1379 info->TargetSUBFee = &info->bfee_entry[idx];
1380 _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
1381 info->TargetSUBFee->bSuspendSUCap = _FALSE;
1382 }
1383 }
1384 } else if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) {
1385 info->beamformee_su_cnt -= 1;
1386
1387 /* When the target SU BFee leaves, disable workaround */
1388 if ((_TRUE == info->bEnableSUTxBFWorkAround)
1389 && (entry == info->TargetSUBFee)) {
1390 entry->bSuspendSUCap = _TRUE;
1391 info->TargetSUBFee = NULL;
1392 _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO));
1393 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0);
1394 }
1395 }
1396
1397 if (info->beamformee_mu_cnt == 0)
1398 info->beamforming_cap &= ~BEAMFORMER_CAP_VHT_MU;
1399 if (info->beamformee_su_cnt == 0)
1400 info->beamforming_cap &= ~(BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT);
1401
1402 _sounding_update_min_period(adapter, 0, _TRUE);
1403 }
1404
_bfee_get_entry_cap_by_macid(PADAPTER adapter,u8 macid)1405 static enum beamforming_cap _bfee_get_entry_cap_by_macid(PADAPTER adapter, u8 macid)
1406 {
1407 struct beamforming_info *info;
1408 struct beamformee_entry *bfee;
1409 u8 i;
1410
1411
1412 info = GET_BEAMFORM_INFO(adapter);
1413
1414 for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) {
1415 bfee = &info->bfee_entry[i];
1416 if (bfee->used == _FALSE)
1417 continue;
1418 if (bfee->mac_id == macid)
1419 return bfee->cap;
1420 }
1421
1422 return BEAMFORMING_CAP_NONE;
1423 }
1424
_beamforming_enter(PADAPTER adapter,void * p)1425 static void _beamforming_enter(PADAPTER adapter, void *p)
1426 {
1427 struct mlme_priv *mlme;
1428 struct ht_priv *htpriv;
1429 #ifdef CONFIG_80211AC_VHT
1430 struct vht_priv *vhtpriv;
1431 #endif
1432 struct mlme_ext_priv *mlme_ext;
1433 struct sta_info *sta, *sta_copy;
1434 struct beamforming_info *info;
1435 struct beamformer_entry *bfer = NULL;
1436 struct beamformee_entry *bfee = NULL;
1437 u8 wireless_mode;
1438 u8 sta_bf_cap;
1439 u8 sounding_dim = 0; /* number of sounding dimensions */
1440 u8 comp_steering_num = 0; /* compressed steering number */
1441
1442
1443 mlme = &adapter->mlmepriv;
1444 htpriv = &mlme->htpriv;
1445 #ifdef CONFIG_80211AC_VHT
1446 vhtpriv = &mlme->vhtpriv;
1447 #endif
1448 mlme_ext = &adapter->mlmeextpriv;
1449 info = GET_BEAMFORM_INFO(adapter);
1450
1451 sta_copy = (struct sta_info *)p;
1452 sta = rtw_get_stainfo(&adapter->stapriv, sta_copy->cmn.mac_addr);
1453 if (!sta) {
1454 RTW_ERR("%s: Cann't find STA info for " MAC_FMT "\n",
1455 __FUNCTION__, MAC_ARG(sta_copy->cmn.mac_addr));
1456 return;
1457 }
1458
1459 RTW_INFO("%s: find STA info for " MAC_FMT "\n",
1460 __FUNCTION__, MAC_ARG(sta_copy->cmn.mac_addr));
1461
1462 if (sta != sta_copy) {
1463 RTW_WARN("%s: Origin sta(fake)=%p realsta=%p for " MAC_FMT "\n",
1464 __FUNCTION__, sta_copy, sta, MAC_ARG(sta_copy->cmn.mac_addr));
1465 }
1466
1467 /* The current setting does not support Beaforming */
1468 wireless_mode = sta->wireless_mode;
1469 if ((is_supported_ht(wireless_mode) == _FALSE)
1470 && (is_supported_vht(wireless_mode) == _FALSE)) {
1471 RTW_WARN("%s: Not support HT or VHT mode\n", __FUNCTION__);
1472 return;
1473 }
1474
1475 if ((0 == htpriv->beamform_cap)
1476 #ifdef CONFIG_80211AC_VHT
1477 && (0 == vhtpriv->beamform_cap)
1478 #endif
1479 ) {
1480 RTW_INFO("The configuration disabled Beamforming! Skip...\n");
1481 return;
1482 }
1483
1484 _get_sta_beamform_cap(adapter, sta,
1485 &sta_bf_cap, &sounding_dim, &comp_steering_num);
1486 RTW_INFO("STA Beamforming Capability=0x%02X\n", sta_bf_cap);
1487 if (sta_bf_cap == BEAMFORMING_CAP_NONE)
1488 return;
1489 if ((sta_bf_cap & BEAMFORMEE_CAP_HT_EXPLICIT)
1490 || (sta_bf_cap & BEAMFORMEE_CAP_VHT_SU)
1491 || (sta_bf_cap & BEAMFORMEE_CAP_VHT_MU))
1492 sta_bf_cap |= BEAMFORMEE_CAP;
1493 if ((sta_bf_cap & BEAMFORMER_CAP_HT_EXPLICIT)
1494 || (sta_bf_cap & BEAMFORMER_CAP_VHT_SU)
1495 || (sta_bf_cap & BEAMFORMER_CAP_VHT_MU))
1496 sta_bf_cap |= BEAMFORMER_CAP;
1497
1498 if (sta_bf_cap & BEAMFORMER_CAP) {
1499 /* The other side is beamformer */
1500 bfer = _bfer_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num);
1501 if (!bfer)
1502 RTW_ERR("%s: Fail to allocate bfer entry!\n", __FUNCTION__);
1503 }
1504 if (sta_bf_cap & BEAMFORMEE_CAP) {
1505 /* The other side is beamformee */
1506 bfee = _bfee_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num);
1507 if (!bfee)
1508 RTW_ERR("%s: Fail to allocate bfee entry!\n", __FUNCTION__);
1509 }
1510 if (!bfer && !bfee)
1511 return;
1512
1513 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8*)sta);
1514
1515 /* Perform sounding if there is BFee */
1516 if ((info->beamformee_su_cnt != 0)
1517 || (info->beamformee_mu_cnt != 0)) {
1518 if (SOUNDING_STATE_NONE == info->sounding_info.state) {
1519 info->sounding_info.state = SOUNDING_STATE_INIT;
1520 /* Start sounding after 2 sec */
1521 _set_timer(&info->sounding_timer, 2000);
1522 }
1523 }
1524 }
1525
_beamforming_reset(PADAPTER adapter)1526 static void _beamforming_reset(PADAPTER adapter)
1527 {
1528 RTW_ERR("%s: Not ready!!\n", __FUNCTION__);
1529 }
1530
_beamforming_leave(PADAPTER adapter,u8 * ra)1531 static void _beamforming_leave(PADAPTER adapter, u8 *ra)
1532 {
1533 struct beamforming_info *info;
1534 struct beamformer_entry *bfer = NULL;
1535 struct beamformee_entry *bfee = NULL;
1536 u8 bHwStateAddInit = _FALSE;
1537
1538
1539 RTW_INFO("+%s\n", __FUNCTION__);
1540
1541 info = GET_BEAMFORM_INFO(adapter);
1542 bfer = _bfer_get_entry_by_addr(adapter, ra);
1543 bfee = _bfee_get_entry_by_addr(adapter, ra);
1544
1545 if (!bfer && !bfee) {
1546 RTW_WARN("%s: " MAC_FMT " is neither beamforming ee or er!!\n",
1547 __FUNCTION__, MAC_ARG(ra));
1548 return;
1549 }
1550
1551 if (bfer)
1552 _bfer_remove_entry(adapter, bfer);
1553
1554 if (bfee)
1555 _bfee_remove_entry(adapter, bfee);
1556
1557 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, ra);
1558
1559 /* Stop sounding if there is no any BFee */
1560 if ((info->beamformee_su_cnt == 0)
1561 && (info->beamformee_mu_cnt == 0)) {
1562 _cancel_timer_ex(&info->sounding_timer);
1563 _sounding_init(&info->sounding_info);
1564 }
1565
1566 RTW_INFO("-%s\n", __FUNCTION__);
1567 }
1568
_beamforming_sounding_down(PADAPTER adapter,u8 status)1569 static void _beamforming_sounding_down(PADAPTER adapter, u8 status)
1570 {
1571 struct beamforming_info *info;
1572 struct sounding_info *sounding;
1573 struct beamformee_entry *bfee;
1574
1575
1576 info = GET_BEAMFORM_INFO(adapter);
1577 sounding = &info->sounding_info;
1578
1579 RTW_INFO("+%s: sounding=%d, status=0x%02x\n", __FUNCTION__, sounding->state, status);
1580
1581 if (sounding->state == SOUNDING_STATE_MU_START) {
1582 RTW_INFO("%s: MU sounding done\n", __FUNCTION__);
1583 sounding->state = SOUNDING_STATE_MU_SOUNDDOWN;
1584 RTW_INFO("%s: Set to SOUNDING_STATE_MU_SOUNDDOWN\n", __FUNCTION__);
1585 info->SetHalSoundownOnDemandCnt++;
1586 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);
1587 } else if (sounding->state == SOUNDING_STATE_SU_START) {
1588 RTW_INFO("%s: SU entry[%d] sounding down\n", __FUNCTION__, sounding->su_bfee_curidx);
1589 bfee = &info->bfee_entry[sounding->su_bfee_curidx];
1590 sounding->state = SOUNDING_STATE_SU_SOUNDDOWN;
1591 RTW_INFO("%s: Set to SOUNDING_STATE_SU_SOUNDDOWN\n", __FUNCTION__);
1592
1593 /*
1594 * <tynli_note>
1595 * bfee->bSoundingTimeout this flag still cannot avoid
1596 * old sound down event happens in the new sounding period.
1597 * 2015.12.10
1598 */
1599 if (_TRUE == bfee->bSoundingTimeout) {
1600 RTW_WARN("%s: The entry[%d] is bSoundingTimeout!\n", __FUNCTION__, sounding->su_bfee_curidx);
1601 bfee->bSoundingTimeout = _FALSE;
1602 return;
1603 }
1604
1605 if (_TRUE == status) {
1606 /* success */
1607 bfee->LogStatusFailCnt = 0;
1608 info->SetHalSoundownOnDemandCnt++;
1609 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);
1610 } else if (_TRUE == bfee->bDeleteSounding) {
1611 RTW_WARN("%s: Delete entry[%d] sounding info!\n", __FUNCTION__, sounding->su_bfee_curidx);
1612 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status);
1613 bfee->bDeleteSounding = _FALSE;
1614 } else {
1615 bfee->LogStatusFailCnt++;
1616 RTW_WARN("%s: LogStatusFailCnt=%d\n", __FUNCTION__, bfee->LogStatusFailCnt);
1617 if (bfee->LogStatusFailCnt > 30) {
1618 RTW_ERR("%s: LogStatusFailCnt > 30, Stop SOUNDING!!\n", __FUNCTION__);
1619 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_LEAVE, bfee->mac_addr, ETH_ALEN, 1);
1620 }
1621 }
1622 } else {
1623 RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state);
1624 return;
1625 }
1626
1627 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 0);
1628 }
1629
_c2h_snd_txbf(PADAPTER adapter,u8 * buf,u8 buf_len)1630 static void _c2h_snd_txbf(PADAPTER adapter, u8 *buf, u8 buf_len)
1631 {
1632 struct beamforming_info *info;
1633 u8 res;
1634
1635 info = GET_BEAMFORM_INFO(adapter);
1636
1637 _cancel_timer_ex(&info->sounding_timeout_timer);
1638
1639 res = C2H_SND_TXBF_GET_SND_RESULT(buf) ? _TRUE : _FALSE;
1640 RTW_INFO("+%s: %s\n", __FUNCTION__, res==_TRUE?"Success":"Fail!");
1641
1642 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1);
1643 }
1644
1645 /*
1646 * Description:
1647 * This function is for phydm only
1648 */
rtw_bf_bfee_get_entry_cap_by_macid(void * mlme,u8 macid)1649 enum beamforming_cap rtw_bf_bfee_get_entry_cap_by_macid(void *mlme, u8 macid)
1650 {
1651 PADAPTER adapter;
1652 enum beamforming_cap cap = BEAMFORMING_CAP_NONE;
1653
1654
1655 adapter = mlme_to_adapter((struct mlme_priv *)mlme);
1656 cap = _bfee_get_entry_cap_by_macid(adapter, macid);
1657
1658 return cap;
1659 }
1660
rtw_bf_bfer_get_entry_by_addr(PADAPTER adapter,u8 * ra)1661 struct beamformer_entry *rtw_bf_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra)
1662 {
1663 return _bfer_get_entry_by_addr(adapter, ra);
1664 }
1665
rtw_bf_bfee_get_entry_by_addr(PADAPTER adapter,u8 * ra)1666 struct beamformee_entry *rtw_bf_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra)
1667 {
1668 return _bfee_get_entry_by_addr(adapter, ra);
1669 }
1670
rtw_bf_get_ndpa_packet(PADAPTER adapter,union recv_frame * precv_frame)1671 void rtw_bf_get_ndpa_packet(PADAPTER adapter, union recv_frame *precv_frame)
1672 {
1673 RTW_DBG("+%s\n", __FUNCTION__);
1674 }
1675
rtw_bf_get_report_packet(PADAPTER adapter,union recv_frame * precv_frame)1676 u32 rtw_bf_get_report_packet(PADAPTER adapter, union recv_frame *precv_frame)
1677 {
1678 u32 ret = _SUCCESS;
1679 struct beamforming_info *info;
1680 struct beamformee_entry *bfee = NULL;
1681 u8 *pframe;
1682 u32 frame_len;
1683 u8 *ta;
1684 u8 *frame_body;
1685 u8 category, action;
1686 u8 *pMIMOCtrlField, *pCSIMatrix;
1687 u8 Nc = 0, Nr = 0, CH_W = 0, Ng = 0, CodeBook = 0;
1688 u16 CSIMatrixLen = 0;
1689
1690
1691 RTW_INFO("+%s\n", __FUNCTION__);
1692
1693 info = GET_BEAMFORM_INFO(adapter);
1694 pframe = precv_frame->u.hdr.rx_data;
1695 frame_len = precv_frame->u.hdr.len;
1696
1697 /* Memory comparison to see if CSI report is the same with previous one */
1698 ta = get_addr2_ptr(pframe);
1699 bfee = _bfee_get_entry_by_addr(adapter, ta);
1700 if (!bfee)
1701 return _FAIL;
1702
1703 frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
1704 category = frame_body[0];
1705 action = frame_body[1];
1706
1707 if ((category == RTW_WLAN_CATEGORY_VHT)
1708 && (action == RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING)) {
1709 pMIMOCtrlField = pframe + 26;
1710 Nc = (*pMIMOCtrlField) & 0x7;
1711 Nr = ((*pMIMOCtrlField) & 0x38) >> 3;
1712 CH_W = (((*pMIMOCtrlField) & 0xC0) >> 6);
1713 Ng = (*(pMIMOCtrlField+1)) & 0x3;
1714 CodeBook = ((*(pMIMOCtrlField+1)) & 0x4) >> 2;
1715 /*
1716 * 24+(1+1+3)+2
1717 * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
1718 */
1719 pCSIMatrix = pMIMOCtrlField + 3 + Nc;
1720 CSIMatrixLen = frame_len - 26 - 3 - Nc;
1721 info->TargetCSIInfo.bVHT = _TRUE;
1722 } else if ((category == RTW_WLAN_CATEGORY_HT)
1723 && (action == RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING)) {
1724 pMIMOCtrlField = pframe + 26;
1725 Nc = (*pMIMOCtrlField) & 0x3;
1726 Nr = ((*pMIMOCtrlField) & 0xC) >> 2;
1727 CH_W = ((*pMIMOCtrlField) & 0x10) >> 4;
1728 Ng = ((*pMIMOCtrlField) & 0x60) >> 5;
1729 CodeBook = ((*(pMIMOCtrlField+1)) & 0x6) >> 1;
1730 /*
1731 * 24+(1+1+6)+2
1732 * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
1733 */
1734 pCSIMatrix = pMIMOCtrlField + 6 + Nr;
1735 CSIMatrixLen = frame_len - 26 - 6 - Nr;
1736 info->TargetCSIInfo.bVHT = _FALSE;
1737 }
1738
1739 /* Update current CSI report info */
1740 if ((_TRUE == info->bEnableSUTxBFWorkAround)
1741 && (info->TargetSUBFee == bfee)) {
1742 if ((info->TargetCSIInfo.Nc != Nc) || (info->TargetCSIInfo.Nr != Nr) ||
1743 (info->TargetCSIInfo.ChnlWidth != CH_W) || (info->TargetCSIInfo.Ng != Ng) ||
1744 (info->TargetCSIInfo.CodeBook != CodeBook)) {
1745 info->TargetCSIInfo.Nc = Nc;
1746 info->TargetCSIInfo.Nr = Nr;
1747 info->TargetCSIInfo.ChnlWidth = CH_W;
1748 info->TargetCSIInfo.Ng = Ng;
1749 info->TargetCSIInfo.CodeBook = CodeBook;
1750
1751 rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 1);
1752 }
1753 }
1754
1755 RTW_INFO("%s: pkt type=%d-%d, Nc=%d, Nr=%d, CH_W=%d, Ng=%d, CodeBook=%d\n",
1756 __FUNCTION__, category, action, Nc, Nr, CH_W, Ng, CodeBook);
1757
1758 return ret;
1759 }
1760
rtw_bf_send_vht_gid_mgnt_packet(PADAPTER adapter,u8 * ra,u8 * gid,u8 * position)1761 u8 rtw_bf_send_vht_gid_mgnt_packet(PADAPTER adapter, u8 *ra, u8 *gid, u8 *position)
1762 {
1763 /* General */
1764 struct xmit_priv *xmitpriv;
1765 struct mlme_priv *mlmepriv;
1766 struct xmit_frame *pmgntframe;
1767 /* MISC */
1768 struct pkt_attrib *attrib;
1769 struct rtw_ieee80211_hdr *wlanhdr;
1770 u8 *pframe, *ptr;
1771
1772
1773 xmitpriv = &adapter->xmitpriv;
1774 mlmepriv = &adapter->mlmepriv;
1775
1776 pmgntframe = alloc_mgtxmitframe(xmitpriv);
1777 if (!pmgntframe)
1778 return _FALSE;
1779
1780 /* update attribute */
1781 attrib = &pmgntframe->attrib;
1782 update_mgntframe_attrib(adapter, attrib);
1783 attrib->rate = MGN_6M;
1784 attrib->bwmode = CHANNEL_WIDTH_20;
1785 attrib->subtype = WIFI_ACTION;
1786
1787 _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1788
1789 pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET;
1790 wlanhdr = (struct rtw_ieee80211_hdr *)pframe;
1791
1792 wlanhdr->frame_ctl = 0;
1793 set_frame_sub_type(pframe, attrib->subtype);
1794 set_duration(pframe, 0);
1795 SetFragNum(pframe, 0);
1796 SetSeqNum(pframe, 0);
1797
1798 _rtw_memcpy(wlanhdr->addr1, ra, ETH_ALEN);
1799 _rtw_memcpy(wlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN);
1800 _rtw_memcpy(wlanhdr->addr3, get_bssid(mlmepriv), ETH_ALEN);
1801
1802 pframe[24] = RTW_WLAN_CATEGORY_VHT;
1803 pframe[25] = RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT;
1804 /* Set Membership Status Array */
1805 ptr = pframe + 26;
1806 _rtw_memcpy(ptr, gid, 8);
1807 /* Set User Position Array */
1808 ptr = pframe + 34;
1809 _rtw_memcpy(ptr, position, 16);
1810
1811 attrib->pktlen = 54;
1812 attrib->last_txcmdsz = attrib->pktlen;
1813
1814 dump_mgntframe(adapter, pmgntframe);
1815
1816 return _TRUE;
1817 }
1818
1819 /*
1820 * Description:
1821 * On VHT GID management frame by an MU beamformee.
1822 */
rtw_bf_get_vht_gid_mgnt_packet(PADAPTER adapter,union recv_frame * precv_frame)1823 void rtw_bf_get_vht_gid_mgnt_packet(PADAPTER adapter, union recv_frame *precv_frame)
1824 {
1825 u8 *pframe;
1826 u8 *ta, *gid, *position;
1827
1828
1829 RTW_DBG("+%s\n", __FUNCTION__);
1830
1831 pframe = precv_frame->u.hdr.rx_data;
1832
1833 /* Get address by Addr2 */
1834 ta = get_addr2_ptr(pframe);
1835 /* Remove signaling TA */
1836 ta[0] &= 0xFE;
1837
1838 /* Membership Status Array */
1839 gid = pframe + 26;
1840 /* User Position Array */
1841 position= pframe + 34;
1842
1843 _bfer_set_entry_gid(adapter, ta, gid, position);
1844 }
1845
rtw_bf_init(PADAPTER adapter)1846 void rtw_bf_init(PADAPTER adapter)
1847 {
1848 struct beamforming_info *info;
1849
1850
1851 info = GET_BEAMFORM_INFO(adapter);
1852 info->beamforming_cap = BEAMFORMING_CAP_NONE;
1853 info->beamforming_state = BEAMFORMING_STATE_IDLE;
1854 /*
1855 info->bfee_entry[MAX_BEAMFORMEE_ENTRY_NUM];
1856 info->bfer_entry[MAX_BEAMFORMER_ENTRY_NUM];
1857 */
1858 info->sounding_sequence = 0;
1859 info->beamformee_su_cnt = 0;
1860 info->beamformer_su_cnt = 0;
1861 info->beamformee_su_reg_maping = 0;
1862 info->beamformer_su_reg_maping = 0;
1863 info->beamformee_mu_cnt = 0;
1864 info->beamformer_mu_cnt = 0;
1865 info->beamformee_mu_reg_maping = 0;
1866 info->first_mu_bfee_index = 0xFF;
1867 info->mu_bfer_curidx = 0xFF;
1868 info->cur_csi_rpt_rate = HALMAC_OFDM24;
1869
1870 _sounding_init(&info->sounding_info);
1871 rtw_init_timer(&info->sounding_timer, adapter, _sounding_timer_handler, adapter);
1872 rtw_init_timer(&info->sounding_timeout_timer, adapter, _sounding_timeout_timer_handler, adapter);
1873
1874 info->SetHalBFEnterOnDemandCnt = 0;
1875 info->SetHalBFLeaveOnDemandCnt = 0;
1876 info->SetHalSoundownOnDemandCnt = 0;
1877
1878 info->bEnableSUTxBFWorkAround = _TRUE;
1879 info->TargetSUBFee = NULL;
1880
1881 info->sounding_running = 0;
1882 }
1883
rtw_bf_cmd_hdl(PADAPTER adapter,u8 type,u8 * pbuf)1884 void rtw_bf_cmd_hdl(PADAPTER adapter, u8 type, u8 *pbuf)
1885 {
1886 switch (type) {
1887 case BEAMFORMING_CTRL_ENTER:
1888 _beamforming_enter(adapter, pbuf);
1889 break;
1890
1891 case BEAMFORMING_CTRL_LEAVE:
1892 if (pbuf == NULL)
1893 _beamforming_reset(adapter);
1894 else
1895 _beamforming_leave(adapter, pbuf);
1896 break;
1897
1898 case BEAMFORMING_CTRL_START_PERIOD:
1899 _sounding_handler(adapter);
1900 break;
1901
1902 case BEAMFORMING_CTRL_END_PERIOD:
1903 _beamforming_sounding_down(adapter, *pbuf);
1904 break;
1905
1906 case BEAMFORMING_CTRL_SET_GID_TABLE:
1907 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_SET_GID_TABLE, pbuf);
1908 break;
1909
1910 case BEAMFORMING_CTRL_SET_CSI_REPORT:
1911 rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_CSI_REPORT, pbuf);
1912 break;
1913
1914 default:
1915 break;
1916 }
1917 }
1918
rtw_bf_cmd(PADAPTER adapter,s32 type,u8 * pbuf,s32 size,u8 enqueue)1919 u8 rtw_bf_cmd(PADAPTER adapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)
1920 {
1921 struct cmd_obj *ph2c;
1922 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1923 struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
1924 u8 *wk_buf;
1925 u8 res = _SUCCESS;
1926
1927
1928 if (!enqueue) {
1929 rtw_bf_cmd_hdl(adapter, type, pbuf);
1930 goto exit;
1931 }
1932
1933 ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
1934 if (ph2c == NULL) {
1935 res = _FAIL;
1936 goto exit;
1937 }
1938
1939 pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
1940 if (pdrvextra_cmd_parm == NULL) {
1941 rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
1942 res = _FAIL;
1943 goto exit;
1944 }
1945
1946 if (pbuf != NULL) {
1947 wk_buf = rtw_zmalloc(size);
1948 if (wk_buf == NULL) {
1949 rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
1950 rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
1951 res = _FAIL;
1952 goto exit;
1953 }
1954
1955 _rtw_memcpy(wk_buf, pbuf, size);
1956 } else {
1957 wk_buf = NULL;
1958 size = 0;
1959 }
1960
1961 pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;
1962 pdrvextra_cmd_parm->type = type;
1963 pdrvextra_cmd_parm->size = size;
1964 pdrvextra_cmd_parm->pbuf = wk_buf;
1965
1966 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, CMD_SET_DRV_EXTRA);
1967
1968 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1969
1970 exit:
1971 return res;
1972 }
1973
rtw_bf_update_attrib(PADAPTER adapter,struct pkt_attrib * attrib,struct sta_info * sta)1974 void rtw_bf_update_attrib(PADAPTER adapter, struct pkt_attrib *attrib, struct sta_info *sta)
1975 {
1976 if (sta) {
1977 attrib->txbf_g_id = sta->cmn.bf_info.g_id;
1978 attrib->txbf_p_aid = sta->cmn.bf_info.p_aid;
1979 }
1980 }
1981
rtw_bf_c2h_handler(PADAPTER adapter,u8 id,u8 * buf,u8 buf_len)1982 void rtw_bf_c2h_handler(PADAPTER adapter, u8 id, u8 *buf, u8 buf_len)
1983 {
1984 switch (id) {
1985 case CMD_ID_C2H_SND_TXBF:
1986 _c2h_snd_txbf(adapter, buf, buf_len);
1987 break;
1988 }
1989 }
1990
1991 #define toMbps(bytes, secs) (rtw_division64(bytes >> 17, secs))
rtw_bf_update_traffic(PADAPTER adapter)1992 void rtw_bf_update_traffic(PADAPTER adapter)
1993 {
1994 struct beamforming_info *info;
1995 struct sounding_info *sounding;
1996 struct beamformee_entry *bfee;
1997 struct sta_info *sta;
1998 u8 bfee_cnt, sounding_idx, i;
1999 u16 tp[MAX_BEAMFORMEE_ENTRY_NUM] = {0};
2000 u8 tx_rate[MAX_BEAMFORMEE_ENTRY_NUM] = {0};
2001 u64 tx_bytes, last_bytes;
2002 u32 time;
2003 systime last_timestamp;
2004 u8 set_timer = _FALSE;
2005
2006
2007 info = GET_BEAMFORM_INFO(adapter);
2008 sounding = &info->sounding_info;
2009
2010 /* Check any bfee exist? */
2011 bfee_cnt = info->beamformee_su_cnt + info->beamformee_mu_cnt;
2012 if (bfee_cnt == 0)
2013 return;
2014
2015 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
2016 bfee = &info->bfee_entry[i];
2017 if (_FALSE == bfee->used)
2018 continue;
2019
2020 sta = rtw_get_stainfo(&adapter->stapriv, bfee->mac_addr);
2021 if (!sta) {
2022 RTW_ERR("%s: Cann't find sta_info for " MAC_FMT "!\n", __FUNCTION__, MAC_ARG(bfee->mac_addr));
2023 continue;
2024 }
2025
2026 last_timestamp = bfee->tx_timestamp;
2027 last_bytes = bfee->tx_bytes;
2028 bfee->tx_timestamp = rtw_get_current_time();
2029 bfee->tx_bytes = sta->sta_stats.tx_bytes;
2030 if (last_timestamp) {
2031 if (bfee->tx_bytes >= last_bytes)
2032 tx_bytes = bfee->tx_bytes - last_bytes;
2033 else
2034 tx_bytes = bfee->tx_bytes + (~last_bytes);
2035 time = rtw_get_time_interval_ms(last_timestamp, bfee->tx_timestamp);
2036 time = (time > 1000) ? time/1000 : 1;
2037 tp[i] = toMbps(tx_bytes, time);
2038 tx_rate[i] = rtw_get_current_tx_rate(adapter, sta);
2039 RTW_INFO("%s: BFee idx(%d), MadId(%d), TxTP=%lld bytes (%d Mbps), txrate=%d\n",
2040 __FUNCTION__, i, bfee->mac_id, tx_bytes, tp[i], tx_rate[i]);
2041 }
2042 }
2043
2044 sounding_idx = phydm_get_beamforming_sounding_info(GET_PDM_ODM(adapter), tp, MAX_BEAMFORMEE_ENTRY_NUM, tx_rate);
2045
2046 for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) {
2047 bfee = &info->bfee_entry[i];
2048 if (_FALSE == bfee->used) {
2049 if (sounding_idx & BIT(i))
2050 RTW_WARN("%s: bfee(%d) not in used but need sounding?!\n", __FUNCTION__, i);
2051 continue;
2052 }
2053
2054 if (sounding_idx & BIT(i)) {
2055 if (_FALSE == bfee->bApplySounding) {
2056 bfee->bApplySounding = _TRUE;
2057 bfee->SoundCnt = 0;
2058 set_timer = _TRUE;
2059 }
2060 } else {
2061 if (_TRUE == bfee->bApplySounding) {
2062 bfee->bApplySounding = _FALSE;
2063 bfee->bDeleteSounding = _TRUE;
2064 bfee->SoundCnt = 0;
2065 set_timer = _TRUE;
2066 }
2067 }
2068 }
2069
2070 if (_TRUE == set_timer) {
2071 if (SOUNDING_STATE_NONE == info->sounding_info.state) {
2072 info->sounding_info.state = SOUNDING_STATE_INIT;
2073 _set_timer(&info->sounding_timer, 0);
2074 }
2075 }
2076 }
2077
2078 #else /* !RTW_BEAMFORMING_VERSION_2 */
2079
2080 /*PHYDM_BF - (BEAMFORMING_SUPPORT == 1)*/
rtw_beamforming_get_report_frame(PADAPTER Adapter,union recv_frame * precv_frame)2081 u32 rtw_beamforming_get_report_frame(PADAPTER Adapter, union recv_frame *precv_frame)
2082 {
2083 u32 ret = _SUCCESS;
2084
2085 PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
2086 struct dm_struct *pDM_Odm = &(pHalData->odmpriv);
2087
2088 ret = beamforming_get_report_frame(pDM_Odm, precv_frame);
2089 return ret;
2090 }
2091
rtw_beamforming_get_ndpa_frame(PADAPTER Adapter,union recv_frame * precv_frame)2092 void rtw_beamforming_get_ndpa_frame(PADAPTER Adapter, union recv_frame *precv_frame)
2093 {
2094 PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter);
2095 struct dm_struct *pDM_Odm = &(pHalData->odmpriv);
2096
2097 beamforming_get_ndpa_frame(pDM_Odm, precv_frame);
2098 }
2099
beamforming_wk_hdl(_adapter * padapter,u8 type,u8 * pbuf)2100 void beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf)
2101 {
2102 PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);
2103 struct dm_struct *pDM_Odm = &(pHalData->odmpriv);
2104
2105 /*(BEAMFORMING_SUPPORT == 1)- for PHYDM beamfoming*/
2106 switch (type) {
2107 case BEAMFORMING_CTRL_ENTER: {
2108 struct sta_info *psta = (void *)pbuf;
2109 u16 staIdx = psta->cmn.mac_id;
2110
2111 beamforming_enter(pDM_Odm, staIdx, adapter_mac_addr(psta->padapter));
2112 break;
2113 }
2114 case BEAMFORMING_CTRL_LEAVE:
2115 beamforming_leave(pDM_Odm, pbuf);
2116 break;
2117 default:
2118 break;
2119
2120 }
2121 }
2122
beamforming_wk_cmd(_adapter * padapter,s32 type,u8 * pbuf,s32 size,u8 enqueue)2123 u8 beamforming_wk_cmd(_adapter *padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)
2124 {
2125 struct cmd_obj *ph2c;
2126 struct drvextra_cmd_parm *pdrvextra_cmd_parm;
2127 struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
2128 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
2129 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
2130 u8 res = _SUCCESS;
2131
2132 /*20170214 ad_hoc mode and mp_mode not support BF*/
2133 if ((padapter->registrypriv.mp_mode == 1)
2134 || (pmlmeinfo->state == WIFI_FW_ADHOC_STATE))
2135 return res;
2136
2137 if (enqueue) {
2138 u8 *wk_buf;
2139
2140 ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
2141 if (ph2c == NULL) {
2142 res = _FAIL;
2143 goto exit;
2144 }
2145
2146 pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
2147 if (pdrvextra_cmd_parm == NULL) {
2148 rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
2149 res = _FAIL;
2150 goto exit;
2151 }
2152
2153 if (pbuf != NULL) {
2154 wk_buf = rtw_zmalloc(size);
2155 if (wk_buf == NULL) {
2156 rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
2157 rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
2158 res = _FAIL;
2159 goto exit;
2160 }
2161
2162 _rtw_memcpy(wk_buf, pbuf, size);
2163 } else {
2164 wk_buf = NULL;
2165 size = 0;
2166 }
2167
2168 pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;
2169 pdrvextra_cmd_parm->type = type;
2170 pdrvextra_cmd_parm->size = size;
2171 pdrvextra_cmd_parm->pbuf = wk_buf;
2172
2173 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, CMD_SET_DRV_EXTRA);
2174
2175 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
2176 } else
2177 beamforming_wk_hdl(padapter, type, pbuf);
2178
2179 exit:
2180
2181
2182 return res;
2183 }
2184
update_attrib_txbf_info(_adapter * padapter,struct pkt_attrib * pattrib,struct sta_info * psta)2185 void update_attrib_txbf_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta)
2186 {
2187 if (psta) {
2188 pattrib->txbf_g_id = psta->cmn.bf_info.g_id;
2189 pattrib->txbf_p_aid = psta->cmn.bf_info.p_aid;
2190 }
2191 }
2192 #endif /* !RTW_BEAMFORMING_VERSION_2 */
2193
2194 #endif /* CONFIG_BEAMFORMING */
2195