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 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
16 *
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
21 *
22 * Larry Finger <Larry.Finger@lwfinger.net>
23 *
24 *****************************************************************************/
25
26 #include "mp_precomp.h"
27 #include "phydm_precomp.h"
28
29 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
30 #if WPP_SOFTWARE_TRACE
31 #include "phydm_beamforming.tmh"
32 #endif
33 #endif
34
35 #ifdef PHYDM_BEAMFORMING_SUPPORT
36
phydm_get_txbf_device_num(void * dm_void,u8 macid)37 void phydm_get_txbf_device_num(
38 void *dm_void,
39 u8 macid)
40 {
41 #if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) /*@For BDC*/
42 #if (DM_ODM_SUPPORT_TYPE == ODM_AP)
43
44 struct dm_struct *dm = (struct dm_struct *)dm_void;
45 struct cmn_sta_info *sta = dm->phydm_sta_info[macid];
46 struct bf_cmn_info *bf = NULL;
47 struct _BF_DIV_COEX_ *dm_bdc_table = &dm->dm_bdc_table;
48 u8 act_as_bfer = 0;
49 u8 act_as_bfee = 0;
50
51 if (!(dm->support_ability & ODM_BB_ANT_DIV))
52 return;
53
54 if (is_sta_active(sta)) {
55 bf = &(sta->bf_info);
56 } else {
57 PHYDM_DBG(dm, DBG_TXBF, "[Warning] %s invalid sta_info\n",
58 __func__);
59 return;
60 }
61
62 if (sta->support_wireless_set & WIRELESS_VHT) {
63 if (bf->vht_beamform_cap & BEAMFORMING_VHT_BEAMFORMEE_ENABLE)
64 act_as_bfer = 1;
65
66 if (bf->vht_beamform_cap & BEAMFORMING_VHT_BEAMFORMER_ENABLE)
67 act_as_bfee = 1;
68
69 } else if (sta->support_wireless_set & WIRELESS_HT) {
70 if (bf->ht_beamform_cap & BEAMFORMING_HT_BEAMFORMEE_ENABLE)
71 act_as_bfer = 1;
72
73 if (bf->ht_beamform_cap & BEAMFORMING_HT_BEAMFORMER_ENABLE)
74 act_as_bfee = 1;
75 }
76
77 if (act_as_bfer)
78 { /* Our Device act as BFer */
79 dm_bdc_table->w_bfee_client[macid] = true;
80 dm_bdc_table->num_txbfee_client++;
81 }
82 else
83 dm_bdc_table->w_bfee_client[macid] = false;
84
85 if (act_as_bfee)
86 { /* Our Device act as BFee */
87 dm_bdc_table->w_bfer_client[macid] = true;
88 dm_bdc_table->num_txbfer_client++;
89 }
90 else
91 dm_bdc_table->w_bfer_client[macid] = false;
92
93 #endif
94 #endif
95 }
96
97 struct _RT_BEAMFORM_STAINFO *
phydm_sta_info_init(struct dm_struct * dm,u16 sta_idx,u8 * my_mac_addr)98 phydm_sta_info_init(struct dm_struct *dm, u16 sta_idx, u8 *my_mac_addr)
99 {
100 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
101 struct _RT_BEAMFORM_STAINFO *entry = &beam_info->beamform_sta_info;
102 struct cmn_sta_info *cmn_sta = dm->phydm_sta_info[sta_idx];
103 //void *adapter = dm->adapter;
104 ADAPTER * adapter = dm->adapter;
105 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
106 PMGNT_INFO p_MgntInfo = &((adapter)->MgntInfo);
107 PRT_HIGH_THROUGHPUT p_ht_info = GET_HT_INFO(p_MgntInfo);
108 PRT_VERY_HIGH_THROUGHPUT p_vht_info = GET_VHT_INFO(p_MgntInfo);
109 #endif
110
111 if (!is_sta_active(cmn_sta)) {
112 PHYDM_DBG(dm, DBG_TXBF, "%s => sta_info(mac_id:%d) failed\n",
113 __func__, sta_idx);
114 #if (DM_ODM_SUPPORT_TYPE == ODM_CE)
115 rtw_warn_on(1);
116 #endif
117
118 return entry;
119 }
120
121 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
122 /*odm_move_memory(dm, (PVOID)(entry->my_mac_addr),*/
123 /*(PVOID)(adapter->CurrentAddress), 6);*/
124 odm_move_memory(dm, entry->my_mac_addr, my_mac_addr, 6);
125 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
126 /*odm_move_memory(dm, entry->my_mac_addr,*/
127 /*adapter_mac_addr(sta->padapter), 6);*/
128 odm_move_memory(dm, entry->my_mac_addr, my_mac_addr, 6);
129 #endif
130
131 entry->aid = cmn_sta->aid;
132 entry->ra = cmn_sta->mac_addr;
133 entry->mac_id = cmn_sta->mac_id;
134 entry->bw = cmn_sta->bw_mode;
135 entry->cur_beamform = cmn_sta->bf_info.ht_beamform_cap;
136 entry->ht_beamform_cap = cmn_sta->bf_info.ht_beamform_cap;
137
138 #if ODM_IC_11AC_SERIES_SUPPORT
139 if (cmn_sta->support_wireless_set & WIRELESS_VHT) {
140 entry->cur_beamform_vht = cmn_sta->bf_info.vht_beamform_cap;
141 entry->vht_beamform_cap = cmn_sta->bf_info.vht_beamform_cap;
142 }
143 #endif
144
145 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) /*To Be Removed */
146 entry->ht_beamform_cap = p_ht_info->HtBeamformCap; /*To Be Removed*/
147 entry->vht_beamform_cap = p_vht_info->VhtBeamformCap; /*To Be Removed*/
148
149 if (sta_idx == 0) { /*@client mode*/
150 #if ODM_IC_11AC_SERIES_SUPPORT
151 if (cmn_sta->support_wireless_set & WIRELESS_VHT)
152 entry->cur_beamform_vht = p_vht_info->VhtCurBeamform;
153 #endif
154 }
155 #endif
156
157 PHYDM_DBG(dm, DBG_TXBF, "wireless_set = 0x%x, staidx = %d\n",
158 cmn_sta->support_wireless_set, sta_idx);
159 PHYDM_DBG(dm, DBG_TXBF,
160 "entry->cur_beamform = 0x%x, entry->cur_beamform_vht = 0x%x\n",
161 entry->cur_beamform, entry->cur_beamform_vht);
162 return entry;
163 }
phydm_sta_info_update(struct dm_struct * dm,u16 sta_idx,struct _RT_BEAMFORMEE_ENTRY * beamform_entry)164 void phydm_sta_info_update(
165 struct dm_struct *dm,
166 u16 sta_idx,
167 struct _RT_BEAMFORMEE_ENTRY *beamform_entry)
168 {
169 struct cmn_sta_info *sta = dm->phydm_sta_info[sta_idx];
170
171 if (!is_sta_active(sta))
172 return;
173
174 sta->bf_info.p_aid = beamform_entry->p_aid;
175 sta->bf_info.g_id = beamform_entry->g_id;
176 }
177
178 struct _RT_BEAMFORMEE_ENTRY *
phydm_beamforming_get_bfee_entry_by_addr(void * dm_void,u8 * RA,u8 * idx)179 phydm_beamforming_get_bfee_entry_by_addr(
180 void *dm_void,
181 u8 *RA,
182 u8 *idx)
183 {
184 struct dm_struct *dm = (struct dm_struct *)dm_void;
185 u8 i = 0;
186 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
187
188 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
189 if (beam_info->beamformee_entry[i].is_used && (eq_mac_addr(RA, beam_info->beamformee_entry[i].mac_addr))) {
190 *idx = i;
191 return &beam_info->beamformee_entry[i];
192 }
193 }
194
195 return NULL;
196 }
197
198 struct _RT_BEAMFORMER_ENTRY *
phydm_beamforming_get_bfer_entry_by_addr(void * dm_void,u8 * TA,u8 * idx)199 phydm_beamforming_get_bfer_entry_by_addr(
200 void *dm_void,
201 u8 *TA,
202 u8 *idx)
203 {
204 struct dm_struct *dm = (struct dm_struct *)dm_void;
205 u8 i = 0;
206 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
207
208 for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
209 if (beam_info->beamformer_entry[i].is_used && (eq_mac_addr(TA, beam_info->beamformer_entry[i].mac_addr))) {
210 *idx = i;
211 return &beam_info->beamformer_entry[i];
212 }
213 }
214
215 return NULL;
216 }
217
218 struct _RT_BEAMFORMEE_ENTRY *
phydm_beamforming_get_entry_by_mac_id(void * dm_void,u8 mac_id,u8 * idx)219 phydm_beamforming_get_entry_by_mac_id(
220 void *dm_void,
221 u8 mac_id,
222 u8 *idx)
223 {
224 struct dm_struct *dm = (struct dm_struct *)dm_void;
225 u8 i = 0;
226 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
227
228 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
229 if (beam_info->beamformee_entry[i].is_used && mac_id == beam_info->beamformee_entry[i].mac_id) {
230 *idx = i;
231 return &beam_info->beamformee_entry[i];
232 }
233 }
234
235 return NULL;
236 }
237
238 enum beamforming_cap
phydm_beamforming_get_entry_beam_cap_by_mac_id(void * dm_void,u8 mac_id)239 phydm_beamforming_get_entry_beam_cap_by_mac_id(
240 void *dm_void,
241 u8 mac_id)
242 {
243 struct dm_struct *dm = (struct dm_struct *)dm_void;
244 u8 i = 0;
245 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
246 enum beamforming_cap beamform_entry_cap = BEAMFORMING_CAP_NONE;
247
248 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
249 if (beam_info->beamformee_entry[i].is_used && mac_id == beam_info->beamformee_entry[i].mac_id) {
250 beamform_entry_cap = beam_info->beamformee_entry[i].beamform_entry_cap;
251 i = BEAMFORMEE_ENTRY_NUM;
252 }
253 }
254
255 return beamform_entry_cap;
256 }
257
258 struct _RT_BEAMFORMEE_ENTRY *
phydm_beamforming_get_free_bfee_entry(void * dm_void,u8 * idx)259 phydm_beamforming_get_free_bfee_entry(
260 void *dm_void,
261 u8 *idx)
262 {
263 struct dm_struct *dm = (struct dm_struct *)dm_void;
264 u8 i = 0;
265 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
266
267 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
268 if (beam_info->beamformee_entry[i].is_used == false) {
269 *idx = i;
270 return &beam_info->beamformee_entry[i];
271 }
272 }
273 return NULL;
274 }
275
276 struct _RT_BEAMFORMER_ENTRY *
phydm_beamforming_get_free_bfer_entry(void * dm_void,u8 * idx)277 phydm_beamforming_get_free_bfer_entry(
278 void *dm_void,
279 u8 *idx)
280 {
281 struct dm_struct *dm = (struct dm_struct *)dm_void;
282 u8 i = 0;
283 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
284
285 PHYDM_DBG(dm, DBG_TXBF, "%s ===>\n", __func__);
286
287 for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
288 if (beam_info->beamformer_entry[i].is_used == false) {
289 *idx = i;
290 return &beam_info->beamformer_entry[i];
291 }
292 }
293 return NULL;
294 }
295
296 /*@
297 * Description: Get the first entry index of MU Beamformee.
298 *
299 * Return value: index of the first MU sta.
300 *
301 * 2015.05.25. Created by tynli.
302 *
303 */
phydm_beamforming_get_first_mu_bfee_entry_idx(void * dm_void)304 u8 phydm_beamforming_get_first_mu_bfee_entry_idx(
305 void *dm_void)
306 {
307 struct dm_struct *dm = (struct dm_struct *)dm_void;
308 u8 idx = 0xFF;
309 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
310 boolean is_found = false;
311
312 for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
313 if (beam_info->beamformee_entry[idx].is_used && beam_info->beamformee_entry[idx].is_mu_sta) {
314 PHYDM_DBG(dm, DBG_TXBF, "[%s] idx=%d!\n", __func__,
315 idx);
316 is_found = true;
317 break;
318 }
319 }
320
321 if (!is_found)
322 idx = 0xFF;
323
324 return idx;
325 }
326
327 /*@Add SU BFee and MU BFee*/
328 struct _RT_BEAMFORMEE_ENTRY *
beamforming_add_bfee_entry(void * dm_void,struct _RT_BEAMFORM_STAINFO * sta,enum beamforming_cap beamform_cap,u8 num_of_sounding_dim,u8 comp_steering_num_of_bfer,u8 * idx)329 beamforming_add_bfee_entry(
330 void *dm_void,
331 struct _RT_BEAMFORM_STAINFO *sta,
332 enum beamforming_cap beamform_cap,
333 u8 num_of_sounding_dim,
334 u8 comp_steering_num_of_bfer,
335 u8 *idx)
336 {
337 struct dm_struct *dm = (struct dm_struct *)dm_void;
338 struct _RT_BEAMFORMEE_ENTRY *entry = phydm_beamforming_get_free_bfee_entry(dm, idx);
339
340 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
341
342 if (entry != NULL) {
343 entry->is_used = true;
344 entry->aid = sta->aid;
345 entry->mac_id = sta->mac_id;
346 entry->sound_bw = sta->bw;
347 odm_move_memory(dm, entry->my_mac_addr, sta->my_mac_addr, 6);
348
349 if (phydm_acting_determine(dm, phydm_acting_as_ap)) {
350 /*@BSSID[44:47] xor BSSID[40:43]*/
351 u16 bssid = ((sta->my_mac_addr[5] & 0xf0) >> 4) ^ (sta->my_mac_addr[5] & 0xf);
352 /*@(dec(A) + dec(B)*32) mod 512*/
353 entry->p_aid = (sta->aid + bssid * 32) & 0x1ff;
354 entry->g_id = 63;
355 PHYDM_DBG(dm, DBG_TXBF,
356 "%s: BFee P_AID addressed to STA=%d\n",
357 __func__, entry->p_aid);
358 } else if (phydm_acting_determine(dm, phydm_acting_as_ibss)) {
359 /*@ad hoc mode*/
360 entry->p_aid = 0;
361 entry->g_id = 63;
362 PHYDM_DBG(dm, DBG_TXBF, "%s: BFee P_AID as IBSS=%d\n",
363 __func__, entry->p_aid);
364 } else {
365 /*@client mode*/
366 entry->p_aid = sta->ra[5];
367 /*@BSSID[39:47]*/
368 entry->p_aid = (entry->p_aid << 1) | (sta->ra[4] >> 7);
369 entry->g_id = 0;
370 PHYDM_DBG(dm, DBG_TXBF,
371 "%s: BFee P_AID addressed to AP=0x%X\n",
372 __func__, entry->p_aid);
373 }
374 cp_mac_addr(entry->mac_addr, sta->ra);
375 entry->is_txbf = false;
376 entry->is_sound = false;
377 entry->sound_period = 400;
378 entry->beamform_entry_cap = beamform_cap;
379 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
380
381 /* @entry->log_seq = 0xff; Move to beamforming_add_bfer_entry*/
382 /* @entry->log_retry_cnt = 0; Move to beamforming_add_bfer_entry*/
383 /* @entry->LogSuccessCnt = 0; Move to beamforming_add_bfer_entry*/
384
385 entry->log_status_fail_cnt = 0;
386
387 entry->num_of_sounding_dim = num_of_sounding_dim;
388 entry->comp_steering_num_of_bfer = comp_steering_num_of_bfer;
389
390 if (beamform_cap & BEAMFORMER_CAP_VHT_MU) {
391 dm->beamforming_info.beamformee_mu_cnt += 1;
392 entry->is_mu_sta = true;
393 dm->beamforming_info.first_mu_bfee_index = phydm_beamforming_get_first_mu_bfee_entry_idx(dm);
394 } else if (beamform_cap & (BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP_HT_EXPLICIT)) {
395 dm->beamforming_info.beamformee_su_cnt += 1;
396 entry->is_mu_sta = false;
397 }
398
399 return entry;
400 } else
401 return NULL;
402 }
403
404 /*@Add SU BFee and MU BFer*/
405 struct _RT_BEAMFORMER_ENTRY *
beamforming_add_bfer_entry(void * dm_void,struct _RT_BEAMFORM_STAINFO * sta,enum beamforming_cap beamform_cap,u8 num_of_sounding_dim,u8 * idx)406 beamforming_add_bfer_entry(
407 void *dm_void,
408 struct _RT_BEAMFORM_STAINFO *sta,
409 enum beamforming_cap beamform_cap,
410 u8 num_of_sounding_dim,
411 u8 *idx)
412 {
413 struct dm_struct *dm = (struct dm_struct *)dm_void;
414 struct _RT_BEAMFORMER_ENTRY *entry = phydm_beamforming_get_free_bfer_entry(dm, idx);
415
416 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
417
418 if (entry != NULL) {
419 entry->is_used = true;
420 odm_move_memory(dm, entry->my_mac_addr, sta->my_mac_addr, 6);
421 if (phydm_acting_determine(dm, phydm_acting_as_ap)) {
422 /*@BSSID[44:47] xor BSSID[40:43]*/
423 u16 bssid = ((sta->my_mac_addr[5] & 0xf0) >> 4) ^ (sta->my_mac_addr[5] & 0xf);
424
425 entry->p_aid = (sta->aid + bssid * 32) & 0x1ff;
426 entry->g_id = 63;
427 /*@(dec(A) + dec(B)*32) mod 512*/
428 } else if (phydm_acting_determine(dm, phydm_acting_as_ibss)) {
429 entry->p_aid = 0;
430 entry->g_id = 63;
431 } else {
432 entry->p_aid = sta->ra[5];
433 /*@BSSID[39:47]*/
434 entry->p_aid = (entry->p_aid << 1) | (sta->ra[4] >> 7);
435 entry->g_id = 0;
436 PHYDM_DBG(dm, DBG_TXBF,
437 "%s: P_AID addressed to AP=0x%X\n", __func__,
438 entry->p_aid);
439 }
440
441 cp_mac_addr(entry->mac_addr, sta->ra);
442 entry->beamform_entry_cap = beamform_cap;
443
444 entry->pre_log_seq = 0; /*@Modified by Jeffery @2015-04-13*/
445 entry->log_seq = 0; /*@Modified by Jeffery @2014-10-29*/
446 entry->log_retry_cnt = 0; /*@Modified by Jeffery @2014-10-29*/
447 entry->log_success = 0; /*@log_success is NOT needed to be accumulated, so LogSuccessCnt->log_success, 2015-04-13, Jeffery*/
448 entry->clock_reset_times = 0; /*@Modified by Jeffery @2015-04-13*/
449
450 entry->num_of_sounding_dim = num_of_sounding_dim;
451
452 if (beamform_cap & BEAMFORMEE_CAP_VHT_MU) {
453 dm->beamforming_info.beamformer_mu_cnt += 1;
454 entry->is_mu_ap = true;
455 entry->aid = sta->aid;
456 } else if (beamform_cap & (BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP_HT_EXPLICIT)) {
457 dm->beamforming_info.beamformer_su_cnt += 1;
458 entry->is_mu_ap = false;
459 }
460
461 return entry;
462 } else
463 return NULL;
464 }
465
466 /* Used for beamforming_start_v1 */
phydm_beamforming_ndpa_rate(void * dm_void,enum channel_width BW,u8 rate)467 void phydm_beamforming_ndpa_rate(
468 void *dm_void,
469 enum channel_width BW,
470 u8 rate)
471 {
472 u16 ndpa_rate = rate;
473 struct dm_struct *dm = (struct dm_struct *)dm_void;
474
475 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
476
477 if (ndpa_rate == 0) {
478 if (dm->rssi_min > 30) /* @link RSSI > 30% */
479 ndpa_rate = ODM_RATE24M;
480 else
481 ndpa_rate = ODM_RATE6M;
482 }
483
484 if (ndpa_rate < ODM_RATEMCS0)
485 BW = (enum channel_width)CHANNEL_WIDTH_20;
486
487 ndpa_rate = (ndpa_rate << 8) | BW;
488 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_RATE, (u8 *)&ndpa_rate);
489 }
490
491 /* Used for beamforming_start_sw and beamforming_start_fw */
phydm_beamforming_dym_ndpa_rate(void * dm_void)492 void phydm_beamforming_dym_ndpa_rate(
493 void *dm_void)
494 {
495 u16 ndpa_rate = ODM_RATE6M, BW;
496 struct dm_struct *dm = (struct dm_struct *)dm_void;
497
498 ndpa_rate = ODM_RATE6M;
499 BW = CHANNEL_WIDTH_20;
500
501 ndpa_rate = ndpa_rate << 8 | BW;
502 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_RATE, (u8 *)&ndpa_rate);
503 PHYDM_DBG(dm, DBG_TXBF, "%s End, NDPA rate = 0x%X\n", __func__,
504 ndpa_rate);
505 }
506
507 /*@
508 * SW Sounding : SW Timer unit 1ms
509 * HW Timer unit (1/32000) s 32k is clock.
510 * FW Sounding : FW Timer unit 10ms
511 */
beamforming_dym_period(void * dm_void,u8 status)512 void beamforming_dym_period(
513 void *dm_void,
514 u8 status)
515 {
516 u8 idx;
517 boolean is_change_period = false;
518 u16 sound_period_sw, sound_period_fw;
519 struct dm_struct *dm = (struct dm_struct *)dm_void;
520
521 struct _RT_BEAMFORMEE_ENTRY *beamform_entry;
522 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
523 struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;
524
525 struct _RT_BEAMFORMEE_ENTRY *entry = &beam_info->beamformee_entry[beam_info->beamformee_cur_idx];
526
527 PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
528
529 /* @3 TODO per-client throughput caculation. */
530
531 if ((*dm->current_tx_tp + *dm->current_rx_tp > 2) && (entry->log_status_fail_cnt <= 20 || status)) {
532 sound_period_sw = 40; /* @40ms */
533 sound_period_fw = 40; /* @From H2C cmd, unit = 10ms */
534 } else {
535 sound_period_sw = 4000; /* @4s */
536 sound_period_fw = 400;
537 }
538 PHYDM_DBG(dm, DBG_TXBF, "[%s]sound_period_sw=%d, sound_period_fw=%d\n",
539 __func__, sound_period_sw, sound_period_fw);
540
541 for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
542 beamform_entry = beam_info->beamformee_entry + idx;
543
544 if (beamform_entry->default_csi_cnt > 20) {
545 /*@Modified by David*/
546 sound_period_sw = 4000;
547 sound_period_fw = 400;
548 }
549
550 PHYDM_DBG(dm, DBG_TXBF, "[%s] period = %d\n", __func__,
551 sound_period_sw);
552 if ((beamform_entry->beamform_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) == 0)
553 continue;
554
555 if (sound_info->sound_mode == SOUNDING_FW_VHT_TIMER || sound_info->sound_mode == SOUNDING_FW_HT_TIMER) {
556 if (beamform_entry->sound_period != sound_period_fw) {
557 beamform_entry->sound_period = sound_period_fw;
558 is_change_period = true; /*Only FW sounding need to send H2C packet to change sound period. */
559 }
560 } else if (beamform_entry->sound_period != sound_period_sw)
561 beamform_entry->sound_period = sound_period_sw;
562 }
563
564 if (is_change_period)
565 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);
566 }
567
568 boolean
beamforming_send_ht_ndpa_packet(void * dm_void,u8 * RA,enum channel_width BW,u8 q_idx)569 beamforming_send_ht_ndpa_packet(
570 void *dm_void,
571 u8 *RA,
572 enum channel_width BW,
573 u8 q_idx)
574 {
575 boolean ret = true;
576 struct dm_struct *dm = (struct dm_struct *)dm_void;
577
578 if (q_idx == BEACON_QUEUE)
579 ret = send_fw_ht_ndpa_packet(dm, RA, BW);
580 else
581 ret = send_sw_ht_ndpa_packet(dm, RA, BW);
582
583 return ret;
584 }
585
586 boolean
beamforming_send_vht_ndpa_packet(void * dm_void,u8 * RA,u16 AID,enum channel_width BW,u8 q_idx)587 beamforming_send_vht_ndpa_packet(
588 void *dm_void,
589 u8 *RA,
590 u16 AID,
591 enum channel_width BW,
592 u8 q_idx)
593 {
594 struct dm_struct *dm = (struct dm_struct *)dm_void;
595 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
596 boolean ret = true;
597
598 hal_com_txbf_set(dm, TXBF_SET_GET_TX_RATE, NULL);
599
600 if (beam_info->tx_bf_data_rate >= ODM_RATEVHTSS3MCS7 && beam_info->tx_bf_data_rate <= ODM_RATEVHTSS3MCS9 && !beam_info->snding3ss)
601 PHYDM_DBG(dm, DBG_TXBF, "@%s: 3SS VHT 789 don't sounding\n",
602 __func__);
603
604 else {
605 if (q_idx == BEACON_QUEUE) /* Send to reserved page => FW NDPA */
606 ret = send_fw_vht_ndpa_packet(dm, RA, AID, BW);
607 else {
608 #ifdef SUPPORT_MU_BF
609 #if (SUPPORT_MU_BF == 1)
610 beam_info->is_mu_sounding = true;
611 ret = send_sw_vht_mu_ndpa_packet(dm, BW);
612 #else
613 beam_info->is_mu_sounding = false;
614 ret = send_sw_vht_ndpa_packet(dm, RA, AID, BW);
615 #endif
616 #else
617 beam_info->is_mu_sounding = false;
618 ret = send_sw_vht_ndpa_packet(dm, RA, AID, BW);
619 #endif
620 }
621 }
622 return ret;
623 }
624
625 enum beamforming_notify_state
phydm_beamfomring_is_sounding(void * dm_void,struct _RT_BEAMFORMING_INFO * beam_info,u8 * idx)626 phydm_beamfomring_is_sounding(
627 void *dm_void,
628 struct _RT_BEAMFORMING_INFO *beam_info,
629 u8 *idx)
630 {
631 enum beamforming_notify_state is_sounding = BEAMFORMING_NOTIFY_NONE;
632 struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;
633 struct dm_struct *dm = (struct dm_struct *)dm_void;
634 u8 i;
635
636 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
637
638 /*@if(( Beamforming_GetBeamCap(beam_info) & BEAMFORMER_CAP) == 0)*/
639 /*@is_sounding = BEAMFORMING_NOTIFY_RESET;*/
640 if (beam_oid_info.sound_oid_mode == sounding_stop_all_timer) {
641 is_sounding = BEAMFORMING_NOTIFY_RESET;
642 goto out;
643 }
644
645 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
646 PHYDM_DBG(dm, DBG_TXBF,
647 "@%s: BFee Entry %d is_used=%d, is_sound=%d\n",
648 __func__, i, beam_info->beamformee_entry[i].is_used,
649 beam_info->beamformee_entry[i].is_sound);
650 if (beam_info->beamformee_entry[i].is_used && !beam_info->beamformee_entry[i].is_sound) {
651 PHYDM_DBG(dm, DBG_TXBF, "%s: Add BFee entry %d\n",
652 __func__, i);
653 *idx = i;
654 if (beam_info->beamformee_entry[i].is_mu_sta)
655 is_sounding = BEAMFORMEE_NOTIFY_ADD_MU;
656 else
657 is_sounding = BEAMFORMEE_NOTIFY_ADD_SU;
658 }
659
660 if (!beam_info->beamformee_entry[i].is_used && beam_info->beamformee_entry[i].is_sound) {
661 PHYDM_DBG(dm, DBG_TXBF, "%s: Delete BFee entry %d\n",
662 __func__, i);
663 *idx = i;
664 if (beam_info->beamformee_entry[i].is_mu_sta)
665 is_sounding = BEAMFORMEE_NOTIFY_DELETE_MU;
666 else
667 is_sounding = BEAMFORMEE_NOTIFY_DELETE_SU;
668 }
669 }
670
671 out:
672 PHYDM_DBG(dm, DBG_TXBF, "%s End, is_sounding = %d\n", __func__,
673 is_sounding);
674 return is_sounding;
675 }
676
677 /* This function is unused */
phydm_beamforming_sounding_idx(void * dm_void,struct _RT_BEAMFORMING_INFO * beam_info)678 u8 phydm_beamforming_sounding_idx(
679 void *dm_void,
680 struct _RT_BEAMFORMING_INFO *beam_info)
681 {
682 u8 idx = 0;
683 struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;
684 struct dm_struct *dm = (struct dm_struct *)dm_void;
685
686 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
687
688 if (beam_oid_info.sound_oid_mode == SOUNDING_SW_HT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_SW_VHT_TIMER ||
689 beam_oid_info.sound_oid_mode == SOUNDING_HW_HT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_HW_VHT_TIMER)
690 idx = beam_oid_info.sound_oid_idx;
691 else {
692 u8 i;
693 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
694 if (beam_info->beamformee_entry[i].is_used && !beam_info->beamformee_entry[i].is_sound) {
695 idx = i;
696 break;
697 }
698 }
699 }
700
701 return idx;
702 }
703
704 enum sounding_mode
phydm_beamforming_sounding_mode(void * dm_void,struct _RT_BEAMFORMING_INFO * beam_info,u8 idx)705 phydm_beamforming_sounding_mode(
706 void *dm_void,
707 struct _RT_BEAMFORMING_INFO *beam_info,
708 u8 idx)
709 {
710 struct dm_struct *dm = (struct dm_struct *)dm_void;
711 u8 support_interface = dm->support_interface;
712
713 struct _RT_BEAMFORMEE_ENTRY beam_entry = beam_info->beamformee_entry[idx];
714 struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;
715 enum sounding_mode mode = beam_oid_info.sound_oid_mode;
716
717 if (beam_oid_info.sound_oid_mode == SOUNDING_SW_VHT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_HW_VHT_TIMER) {
718 if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)
719 mode = beam_oid_info.sound_oid_mode;
720 else
721 mode = sounding_stop_all_timer;
722 } else if (beam_oid_info.sound_oid_mode == SOUNDING_SW_HT_TIMER || beam_oid_info.sound_oid_mode == SOUNDING_HW_HT_TIMER) {
723 if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
724 mode = beam_oid_info.sound_oid_mode;
725 else
726 mode = sounding_stop_all_timer;
727 } else if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_VHT_SU) {
728 if (support_interface == ODM_ITRF_USB && !(dm->support_ic_type & (ODM_RTL8814A | ODM_RTL8822B)))
729 mode = SOUNDING_FW_VHT_TIMER;
730 else
731 mode = SOUNDING_SW_VHT_TIMER;
732 } else if (beam_entry.beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT) {
733 if (support_interface == ODM_ITRF_USB && !(dm->support_ic_type & (ODM_RTL8814A | ODM_RTL8822B)))
734 mode = SOUNDING_FW_HT_TIMER;
735 else
736 mode = SOUNDING_SW_HT_TIMER;
737 } else
738 mode = sounding_stop_all_timer;
739
740 PHYDM_DBG(dm, DBG_TXBF, "[%s] support_interface=%d, mode=%d\n",
741 __func__, support_interface, mode);
742
743 return mode;
744 }
745
phydm_beamforming_sounding_time(void * dm_void,struct _RT_BEAMFORMING_INFO * beam_info,enum sounding_mode mode,u8 idx)746 u16 phydm_beamforming_sounding_time(
747 void *dm_void,
748 struct _RT_BEAMFORMING_INFO *beam_info,
749 enum sounding_mode mode,
750 u8 idx)
751 {
752 u16 sounding_time = 0xffff;
753 struct _RT_BEAMFORMEE_ENTRY beam_entry = beam_info->beamformee_entry[idx];
754 struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;
755 struct dm_struct *dm = (struct dm_struct *)dm_void;
756
757 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
758
759 if (mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_HW_VHT_TIMER)
760 sounding_time = beam_oid_info.sound_oid_period * 32;
761 else if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_SW_VHT_TIMER)
762 /*@Modified by David*/
763 sounding_time = beam_entry.sound_period; /*@beam_oid_info.sound_oid_period;*/
764 else
765 sounding_time = beam_entry.sound_period;
766
767 return sounding_time;
768 }
769
770 enum channel_width
phydm_beamforming_sounding_bw(void * dm_void,struct _RT_BEAMFORMING_INFO * beam_info,enum sounding_mode mode,u8 idx)771 phydm_beamforming_sounding_bw(
772 void *dm_void,
773 struct _RT_BEAMFORMING_INFO *beam_info,
774 enum sounding_mode mode,
775 u8 idx)
776 {
777 enum channel_width sounding_bw = CHANNEL_WIDTH_20;
778 struct _RT_BEAMFORMEE_ENTRY beam_entry = beam_info->beamformee_entry[idx];
779 struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;
780 struct dm_struct *dm = (struct dm_struct *)dm_void;
781
782 if (mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_HW_VHT_TIMER)
783 sounding_bw = beam_oid_info.sound_oid_bw;
784 else if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_SW_VHT_TIMER)
785 /*@Modified by David*/
786 sounding_bw = beam_entry.sound_bw; /*@beam_oid_info.sound_oid_bw;*/
787 else
788 sounding_bw = beam_entry.sound_bw;
789
790 PHYDM_DBG(dm, DBG_TXBF, "%s, sounding_bw=0x%X\n", __func__,
791 sounding_bw);
792
793 return sounding_bw;
794 }
795
796 boolean
phydm_beamforming_select_beam_entry(void * dm_void,struct _RT_BEAMFORMING_INFO * beam_info)797 phydm_beamforming_select_beam_entry(
798 void *dm_void,
799 struct _RT_BEAMFORMING_INFO *beam_info)
800 {
801 struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;
802 struct dm_struct *dm = (struct dm_struct *)dm_void;
803
804 /*@entry.is_sound is different between first and latter NDPA, and should not be used as BFee entry selection*/
805 /*@BTW, latter modification should sync to the selection mechanism of AP/ADSL instead of the fixed sound_idx.*/
806 sound_info->sound_idx = phydm_beamforming_sounding_idx(dm, beam_info);
807 /*sound_info->sound_idx = 0;*/
808
809 if (sound_info->sound_idx < BEAMFORMEE_ENTRY_NUM)
810 sound_info->sound_mode = phydm_beamforming_sounding_mode(dm, beam_info, sound_info->sound_idx);
811 else
812 sound_info->sound_mode = sounding_stop_all_timer;
813
814 if (sounding_stop_all_timer == sound_info->sound_mode) {
815 PHYDM_DBG(dm, DBG_TXBF,
816 "[%s] Return because of sounding_stop_all_timer\n",
817 __func__);
818 return false;
819 } else {
820 sound_info->sound_bw = phydm_beamforming_sounding_bw(dm, beam_info, sound_info->sound_mode, sound_info->sound_idx);
821 sound_info->sound_period = phydm_beamforming_sounding_time(dm, beam_info, sound_info->sound_mode, sound_info->sound_idx);
822 return true;
823 }
824 }
825
826 /*SU BFee Entry Only*/
827 boolean
phydm_beamforming_start_period(void * dm_void)828 phydm_beamforming_start_period(
829 void *dm_void)
830 {
831 struct dm_struct *dm = (struct dm_struct *)dm_void;
832 boolean ret = true;
833 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
834 struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;
835
836 phydm_beamforming_dym_ndpa_rate(dm);
837
838 phydm_beamforming_select_beam_entry(dm, beam_info); /* @Modified */
839
840 if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)
841 odm_set_timer(dm, &beam_info->beamforming_timer, sound_info->sound_period);
842 else if (sound_info->sound_mode == SOUNDING_HW_VHT_TIMER || sound_info->sound_mode == SOUNDING_HW_HT_TIMER ||
843 sound_info->sound_mode == SOUNDING_AUTO_VHT_TIMER || sound_info->sound_mode == SOUNDING_AUTO_HT_TIMER) {
844 HAL_HW_TIMER_TYPE timer_type = HAL_TIMER_TXBF;
845 u32 val = (sound_info->sound_period | (timer_type << 16));
846
847 /* @HW timer stop: All IC has the same setting */
848 phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_STOP, (u8 *)(&timer_type));
849 /* odm_write_1byte(dm, 0x15F, 0); */
850 /* @HW timer init: All IC has the same setting, but 92E & 8812A only write 2 bytes */
851 phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_INIT, (u8 *)(&val));
852 /* odm_write_1byte(dm, 0x164, 1); */
853 /* odm_write_4byte(dm, 0x15C, val); */
854 /* @HW timer start: All IC has the same setting */
855 phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_START, (u8 *)(&timer_type));
856 /* odm_write_1byte(dm, 0x15F, 0x5); */
857 } else if (sound_info->sound_mode == SOUNDING_FW_VHT_TIMER || sound_info->sound_mode == SOUNDING_FW_HT_TIMER)
858 ret = beamforming_start_fw(dm, sound_info->sound_idx);
859 else
860 ret = false;
861
862 PHYDM_DBG(dm, DBG_TXBF,
863 "[%s] sound_idx=%d, sound_mode=%d, sound_bw=%d, sound_period=%d\n",
864 __func__, sound_info->sound_idx, sound_info->sound_mode,
865 sound_info->sound_bw, sound_info->sound_period);
866
867 return ret;
868 }
869
870 /* Used after beamforming_leave, and will clear the setting of the "already deleted" entry
871 *SU BFee Entry Only*/
phydm_beamforming_end_period_sw(void * dm_void)872 void phydm_beamforming_end_period_sw(
873 void *dm_void)
874 {
875 struct dm_struct *dm = (struct dm_struct *)dm_void;
876 /*void *adapter = dm->adapter;*/
877 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
878 struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;
879
880 HAL_HW_TIMER_TYPE timer_type = HAL_TIMER_TXBF;
881
882 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
883
884 if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)
885 odm_cancel_timer(dm, &beam_info->beamforming_timer);
886 else if (sound_info->sound_mode == SOUNDING_HW_VHT_TIMER || sound_info->sound_mode == SOUNDING_HW_HT_TIMER ||
887 sound_info->sound_mode == SOUNDING_AUTO_VHT_TIMER || sound_info->sound_mode == SOUNDING_AUTO_HT_TIMER)
888 /*@HW timer stop: All IC has the same setting*/
889 phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_STOP, (u8 *)(&timer_type));
890 /*odm_write_1byte(dm, 0x15F, 0);*/
891 }
892
phydm_beamforming_end_period_fw(void * dm_void)893 void phydm_beamforming_end_period_fw(
894 void *dm_void)
895 {
896 struct dm_struct *dm = (struct dm_struct *)dm_void;
897 u8 idx = 0;
898
899 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);
900 PHYDM_DBG(dm, DBG_TXBF, "[%s]\n", __func__);
901 }
902
903 /*SU BFee Entry Only*/
phydm_beamforming_clear_entry_sw(void * dm_void,boolean is_delete,u8 delete_idx)904 void phydm_beamforming_clear_entry_sw(
905 void *dm_void,
906 boolean is_delete,
907 u8 delete_idx)
908 {
909 u8 idx = 0;
910 struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;
911 struct dm_struct *dm = (struct dm_struct *)dm_void;
912 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
913
914 if (is_delete) {
915 if (delete_idx < BEAMFORMEE_ENTRY_NUM) {
916 beamform_entry = beam_info->beamformee_entry + delete_idx;
917 if (!(!beamform_entry->is_used && beamform_entry->is_sound)) {
918 PHYDM_DBG(dm, DBG_TXBF,
919 "[%s] SW delete_idx is wrong!!!!!\n",
920 __func__);
921 return;
922 }
923 }
924
925 PHYDM_DBG(dm, DBG_TXBF, "[%s] SW delete BFee entry %d\n",
926 __func__, delete_idx);
927 if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSING) {
928 beamform_entry->is_beamforming_in_progress = false;
929 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
930 } else if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSED) {
931 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
932 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS, (u8 *)&delete_idx);
933 }
934 beamform_entry->is_sound = false;
935 return;
936 }
937
938 for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
939 beamform_entry = beam_info->beamformee_entry + idx;
940
941 /*Used after is_sounding=RESET, and will clear the setting of "ever sounded" entry, which is not necessarily be deleted.*/
942 /*This function is mainly used in case "beam_oid_info.sound_oid_mode == sounding_stop_all_timer".*/
943 /*@However, setting oid doesn't delete entries (is_used is still true), new entries may fail to be added in.*/
944
945 if (!beamform_entry->is_sound)
946 continue;
947
948 PHYDM_DBG(dm, DBG_TXBF, "[%s] SW reset BFee entry %d\n",
949 __func__, idx);
950 /*@
951 * If End procedure is
952 * 1. Between (Send NDPA, C2H packet return), reset state to initialized.
953 * After C2H packet return , status bit will be set to zero.
954 *
955 * 2. After C2H packet, then reset state to initialized and clear status bit.
956 */
957
958 if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSING)
959 phydm_beamforming_end_sw(dm, 0);
960 else if (beamform_entry->beamform_entry_state == BEAMFORMING_ENTRY_STATE_PROGRESSED) {
961 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
962 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS, (u8 *)&idx);
963 }
964
965 beamform_entry->is_sound = false;
966 }
967 }
968
phydm_beamforming_clear_entry_fw(void * dm_void,boolean is_delete,u8 delete_idx)969 void phydm_beamforming_clear_entry_fw(
970 void *dm_void,
971 boolean is_delete,
972 u8 delete_idx)
973 {
974 u8 idx = 0;
975 struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;
976 struct dm_struct *dm = (struct dm_struct *)dm_void;
977 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
978
979 if (is_delete) {
980 if (delete_idx < BEAMFORMEE_ENTRY_NUM) {
981 beamform_entry = beam_info->beamformee_entry + delete_idx;
982
983 if (!(!beamform_entry->is_used && beamform_entry->is_sound)) {
984 PHYDM_DBG(dm, DBG_TXBF,
985 "[%s] FW delete_idx is wrong!!!!!\n",
986 __func__);
987 return;
988 }
989 }
990 PHYDM_DBG(dm, DBG_TXBF, "%s: FW delete BFee entry %d\n",
991 __func__, delete_idx);
992 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
993 beamform_entry->is_sound = false;
994 } else {
995 for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
996 beamform_entry = beam_info->beamformee_entry + idx;
997
998 /*Used after is_sounding=RESET, and will clear the setting of "ever sounded" entry, which is not necessarily be deleted.*/
999 /*This function is mainly used in case "beam_oid_info.sound_oid_mode == sounding_stop_all_timer".*/
1000 /*@However, setting oid doesn't delete entries (is_used is still true), new entries may fail to be added in.*/
1001
1002 if (beamform_entry->is_sound) {
1003 PHYDM_DBG(dm, DBG_TXBF,
1004 "[%s]FW reset BFee entry %d\n",
1005 __func__, idx);
1006 /*@
1007 * If End procedure is
1008 * 1. Between (Send NDPA, C2H packet return), reset state to initialized.
1009 * After C2H packet return , status bit will be set to zero.
1010 *
1011 * 2. After C2H packet, then reset state to initialized and clear status bit.
1012 */
1013
1014 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
1015 beamform_entry->is_sound = false;
1016 }
1017 }
1018 }
1019 }
1020
1021 /*@
1022 * Called :
1023 * 1. Add and delete entry : beamforming_enter/beamforming_leave
1024 * 2. FW trigger : Beamforming_SetTxBFen
1025 * 3. Set OID_RT_BEAMFORMING_PERIOD : beamforming_control_v2
1026 */
phydm_beamforming_notify(void * dm_void)1027 void phydm_beamforming_notify(
1028 void *dm_void)
1029 {
1030 u8 idx = BEAMFORMEE_ENTRY_NUM;
1031 enum beamforming_notify_state is_sounding = BEAMFORMING_NOTIFY_NONE;
1032 struct dm_struct *dm = (struct dm_struct *)dm_void;
1033 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1034 struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;
1035
1036 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1037
1038 is_sounding = phydm_beamfomring_is_sounding(dm, beam_info, &idx);
1039
1040 PHYDM_DBG(dm, DBG_TXBF, "%s, Before notify, is_sounding=%d, idx=%d\n",
1041 __func__, is_sounding, idx);
1042 PHYDM_DBG(dm, DBG_TXBF, "%s: beam_info->beamformee_su_cnt = %d\n",
1043 __func__, beam_info->beamformee_su_cnt);
1044
1045 switch (is_sounding) {
1046 case BEAMFORMEE_NOTIFY_ADD_SU:
1047 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_ADD_SU\n",
1048 __func__);
1049 phydm_beamforming_start_period(dm);
1050 break;
1051
1052 case BEAMFORMEE_NOTIFY_DELETE_SU:
1053 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_DELETE_SU\n",
1054 __func__);
1055 if (sound_info->sound_mode == SOUNDING_FW_HT_TIMER || sound_info->sound_mode == SOUNDING_FW_VHT_TIMER) {
1056 phydm_beamforming_clear_entry_fw(dm, true, idx);
1057 if (beam_info->beamformee_su_cnt == 0) { /* @For 2->1 entry, we should not cancel SW timer */
1058 phydm_beamforming_end_period_fw(dm);
1059 PHYDM_DBG(dm, DBG_TXBF, "%s: No BFee left\n",
1060 __func__);
1061 }
1062 } else {
1063 phydm_beamforming_clear_entry_sw(dm, true, idx);
1064 if (beam_info->beamformee_su_cnt == 0) { /* @For 2->1 entry, we should not cancel SW timer */
1065 phydm_beamforming_end_period_sw(dm);
1066 PHYDM_DBG(dm, DBG_TXBF, "%s: No BFee left\n",
1067 __func__);
1068 }
1069 }
1070 break;
1071
1072 case BEAMFORMEE_NOTIFY_ADD_MU:
1073 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_ADD_MU\n",
1074 __func__);
1075 if (beam_info->beamformee_mu_cnt == 2) {
1076 /*@if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)
1077 odm_set_timer(dm, &beam_info->beamforming_timer, sound_info->sound_period);*/
1078 odm_set_timer(dm, &beam_info->beamforming_timer, 1000); /*@Do MU sounding every 1sec*/
1079 } else
1080 PHYDM_DBG(dm, DBG_TXBF,
1081 "%s: Less or larger than 2 MU STAs, not to set timer\n",
1082 __func__);
1083 break;
1084
1085 case BEAMFORMEE_NOTIFY_DELETE_MU:
1086 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_DELETE_MU\n",
1087 __func__);
1088 if (beam_info->beamformee_mu_cnt == 1) {
1089 /*@if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)*/ {
1090 odm_cancel_timer(dm, &beam_info->beamforming_timer);
1091 PHYDM_DBG(dm, DBG_TXBF,
1092 "%s: Less than 2 MU STAs, stop sounding\n",
1093 __func__);
1094 }
1095 }
1096 break;
1097
1098 case BEAMFORMING_NOTIFY_RESET:
1099 if (sound_info->sound_mode == SOUNDING_FW_HT_TIMER || sound_info->sound_mode == SOUNDING_FW_VHT_TIMER) {
1100 phydm_beamforming_clear_entry_fw(dm, false, idx);
1101 phydm_beamforming_end_period_fw(dm);
1102 } else {
1103 phydm_beamforming_clear_entry_sw(dm, false, idx);
1104 phydm_beamforming_end_period_sw(dm);
1105 }
1106
1107 break;
1108
1109 default:
1110 break;
1111 }
1112 }
1113
1114 boolean
beamforming_init_entry(void * dm_void,u16 sta_idx,u8 * bfer_bfee_idx,u8 * my_mac_addr)1115 beamforming_init_entry(void *dm_void, u16 sta_idx, u8 *bfer_bfee_idx,
1116 u8 *my_mac_addr)
1117 {
1118 struct dm_struct *dm = (struct dm_struct *)dm_void;
1119 struct cmn_sta_info *cmn_sta = dm->phydm_sta_info[sta_idx];
1120 struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;
1121 struct _RT_BEAMFORMER_ENTRY *beamformer_entry = NULL;
1122 struct _RT_BEAMFORM_STAINFO *sta = NULL;
1123 enum beamforming_cap beamform_cap = BEAMFORMING_CAP_NONE;
1124 u8 bfer_idx = 0xF, bfee_idx = 0xF;
1125 u8 num_of_sounding_dim = 0, comp_steering_num_of_bfer = 0;
1126
1127 if (!is_sta_active(cmn_sta)) {
1128 PHYDM_DBG(dm, DBG_TXBF, "%s => sta_info(mac_id:%d) failed\n",
1129 __func__, sta_idx);
1130 #if (DM_ODM_SUPPORT_TYPE == ODM_CE)
1131 rtw_warn_on(1);
1132 #endif
1133 return false;
1134 }
1135
1136 sta = phydm_sta_info_init(dm, sta_idx, my_mac_addr);
1137 /*The current setting does not support Beaforming*/
1138 if (BEAMFORMING_CAP_NONE == sta->ht_beamform_cap && BEAMFORMING_CAP_NONE == sta->vht_beamform_cap) {
1139 PHYDM_DBG(dm, DBG_TXBF,
1140 "The configuration disabled Beamforming! Skip...\n");
1141 return false;
1142 }
1143
1144 if (!(cmn_sta->support_wireless_set & (WIRELESS_VHT | WIRELESS_HT)))
1145 return false;
1146 else {
1147 if (cmn_sta->support_wireless_set & WIRELESS_HT) { /*@HT*/
1148 if (TEST_FLAG(sta->cur_beamform, BEAMFORMING_HT_BEAMFORMER_ENABLE)) { /*We are Beamformee because the STA is Beamformer*/
1149 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP_HT_EXPLICIT);
1150 num_of_sounding_dim = (sta->cur_beamform & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6;
1151 }
1152 /*We are Beamformer because the STA is Beamformee*/
1153 if (TEST_FLAG(sta->cur_beamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE) ||
1154 TEST_FLAG(sta->ht_beamform_cap, BEAMFORMING_HT_BEAMFORMER_TEST)) {
1155 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP_HT_EXPLICIT);
1156 comp_steering_num_of_bfer = (sta->cur_beamform & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4;
1157 }
1158 PHYDM_DBG(dm, DBG_TXBF,
1159 "[%s] HT cur_beamform=0x%X, beamform_cap=0x%X\n",
1160 __func__, sta->cur_beamform, beamform_cap);
1161 PHYDM_DBG(dm, DBG_TXBF,
1162 "[%s] HT num_of_sounding_dim=%d, comp_steering_num_of_bfer=%d\n",
1163 __func__, num_of_sounding_dim,
1164 comp_steering_num_of_bfer);
1165 }
1166 #if (ODM_IC_11AC_SERIES_SUPPORT == 1)
1167 if (cmn_sta->support_wireless_set & WIRELESS_VHT) { /*VHT*/
1168
1169 /* We are Beamformee because the STA is SU Beamformer*/
1170 if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) {
1171 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP_VHT_SU);
1172 num_of_sounding_dim = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;
1173 }
1174 /* We are Beamformer because the STA is SU Beamformee*/
1175 if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) ||
1176 TEST_FLAG(sta->vht_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_TEST)) {
1177 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP_VHT_SU);
1178 comp_steering_num_of_bfer = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;
1179 }
1180 /* We are Beamformee because the STA is MU Beamformer*/
1181 if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) {
1182 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP_VHT_MU);
1183 num_of_sounding_dim = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12;
1184 }
1185 /* We are Beamformer because the STA is MU Beamformee*/
1186 if (phydm_acting_determine(dm, phydm_acting_as_ap)) { /* Only AP mode supports to act an MU beamformer */
1187 if (TEST_FLAG(sta->cur_beamform_vht, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE) ||
1188 TEST_FLAG(sta->vht_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_TEST)) {
1189 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP_VHT_MU);
1190 comp_steering_num_of_bfer = (sta->cur_beamform_vht & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8;
1191 }
1192 }
1193 PHYDM_DBG(dm, DBG_TXBF,
1194 "[%s]VHT cur_beamform_vht=0x%X, beamform_cap=0x%X\n",
1195 __func__, sta->cur_beamform_vht,
1196 beamform_cap);
1197 PHYDM_DBG(dm, DBG_TXBF,
1198 "[%s]VHT num_of_sounding_dim=0x%X, comp_steering_num_of_bfer=0x%X\n",
1199 __func__, num_of_sounding_dim,
1200 comp_steering_num_of_bfer);
1201 }
1202 #endif
1203 }
1204
1205 if (beamform_cap == BEAMFORMING_CAP_NONE)
1206 return false;
1207
1208 PHYDM_DBG(dm, DBG_TXBF, "[%s] Self BF Entry Cap = 0x%02X\n", __func__,
1209 beamform_cap);
1210
1211 /*We are BFee, so the entry is BFer*/
1212 if (beamform_cap & (BEAMFORMEE_CAP_VHT_MU | BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP_HT_EXPLICIT)) {
1213 beamformer_entry = phydm_beamforming_get_bfer_entry_by_addr(dm, sta->ra, &bfer_idx);
1214
1215 if (beamformer_entry == NULL) {
1216 beamformer_entry = beamforming_add_bfer_entry(dm, sta, beamform_cap, num_of_sounding_dim, &bfer_idx);
1217 if (beamformer_entry == NULL)
1218 PHYDM_DBG(dm, DBG_TXBF,
1219 "[%s]Not enough BFer entry!!!!!\n",
1220 __func__);
1221 }
1222 }
1223
1224 /*We are BFer, so the entry is BFee*/
1225 if (beamform_cap & (BEAMFORMER_CAP_VHT_MU | BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP_HT_EXPLICIT)) {
1226 beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, sta->ra, &bfee_idx);
1227
1228 /*@if BFeeIdx = 0xF, that represent for no matched MACID among all linked entrys */
1229 PHYDM_DBG(dm, DBG_TXBF, "[%s] Get BFee entry 0x%X by address\n",
1230 __func__, bfee_idx);
1231 if (beamform_entry == NULL) {
1232 beamform_entry = beamforming_add_bfee_entry(dm, sta, beamform_cap, num_of_sounding_dim, comp_steering_num_of_bfer, &bfee_idx);
1233 PHYDM_DBG(dm, DBG_TXBF,
1234 "[%s]: sta->AID=%d, sta->mac_id=%d\n",
1235 __func__, sta->aid, sta->mac_id);
1236
1237 PHYDM_DBG(dm, DBG_TXBF, "[%s]: Add BFee entry %d\n",
1238 __func__, bfee_idx);
1239
1240 if (beamform_entry == NULL)
1241 return false;
1242 else
1243 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
1244 } else {
1245 /*@Entry has been created. If entry is initialing or progressing then errors occur.*/
1246 if (beamform_entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED &&
1247 beamform_entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED)
1248 return false;
1249 else
1250 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
1251 }
1252 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
1253 phydm_sta_info_update(dm, sta_idx, beamform_entry);
1254 }
1255
1256 *bfer_bfee_idx = (bfer_idx << 4) | bfee_idx;
1257 PHYDM_DBG(dm, DBG_TXBF,
1258 "[%s] End: bfer_idx=0x%X, bfee_idx=0x%X, bfer_bfee_idx=0x%X\n",
1259 __func__, bfer_idx, bfee_idx, *bfer_bfee_idx);
1260
1261 return true;
1262 }
1263
beamforming_deinit_entry(void * dm_void,u8 * RA)1264 void beamforming_deinit_entry(
1265 void *dm_void,
1266 u8 *RA)
1267 {
1268 struct dm_struct *dm = (struct dm_struct *)dm_void;
1269 u8 idx = 0;
1270
1271 struct _RT_BEAMFORMER_ENTRY *bfer_entry = phydm_beamforming_get_bfer_entry_by_addr(dm, RA, &idx);
1272 struct _RT_BEAMFORMEE_ENTRY *bfee_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
1273 boolean ret = false;
1274
1275 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1276
1277 if (bfee_entry != NULL) {
1278 PHYDM_DBG(dm, DBG_TXBF, "%s, bfee_entry\n", __func__);
1279 bfee_entry->is_used = false;
1280 bfee_entry->beamform_entry_cap = BEAMFORMING_CAP_NONE;
1281 bfee_entry->is_beamforming_in_progress = false;
1282 if (bfee_entry->is_mu_sta) {
1283 dm->beamforming_info.beamformee_mu_cnt -= 1;
1284 dm->beamforming_info.first_mu_bfee_index = phydm_beamforming_get_first_mu_bfee_entry_idx(dm);
1285 } else
1286 dm->beamforming_info.beamformee_su_cnt -= 1;
1287 ret = true;
1288 }
1289
1290 if (bfer_entry != NULL) {
1291 PHYDM_DBG(dm, DBG_TXBF, "%s, bfer_entry\n", __func__);
1292 bfer_entry->is_used = false;
1293 bfer_entry->beamform_entry_cap = BEAMFORMING_CAP_NONE;
1294 if (bfer_entry->is_mu_ap)
1295 dm->beamforming_info.beamformer_mu_cnt -= 1;
1296 else
1297 dm->beamforming_info.beamformer_su_cnt -= 1;
1298 ret = true;
1299 }
1300
1301 if (ret == true)
1302 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_LEAVE, (u8 *)&idx);
1303
1304 PHYDM_DBG(dm, DBG_TXBF, "%s End, idx = 0x%X\n", __func__, idx);
1305 }
1306
1307 boolean
beamforming_start_v1(void * dm_void,u8 * RA,boolean mode,enum channel_width BW,u8 rate)1308 beamforming_start_v1(
1309 void *dm_void,
1310 u8 *RA,
1311 boolean mode,
1312 enum channel_width BW,
1313 u8 rate)
1314 {
1315 struct dm_struct *dm = (struct dm_struct *)dm_void;
1316 u8 idx = 0;
1317 struct _RT_BEAMFORMEE_ENTRY *entry;
1318 boolean ret = true;
1319 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1320
1321 entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
1322
1323 if (entry->is_used == false) {
1324 entry->is_beamforming_in_progress = false;
1325 return false;
1326 } else {
1327 if (entry->is_beamforming_in_progress)
1328 return false;
1329
1330 entry->is_beamforming_in_progress = true;
1331
1332 if (mode == 1) {
1333 if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)) {
1334 entry->is_beamforming_in_progress = false;
1335 return false;
1336 }
1337 } else if (mode == 0) {
1338 if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)) {
1339 entry->is_beamforming_in_progress = false;
1340 return false;
1341 }
1342 }
1343
1344 if (entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED && entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
1345 entry->is_beamforming_in_progress = false;
1346 return false;
1347 } else {
1348 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
1349 entry->is_sound = true;
1350 }
1351 }
1352
1353 entry->sound_bw = BW;
1354 beam_info->beamformee_cur_idx = idx;
1355 phydm_beamforming_ndpa_rate(dm, BW, rate);
1356 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS, (u8 *)&idx);
1357
1358 if (mode == 1)
1359 ret = beamforming_send_ht_ndpa_packet(dm, RA, BW, NORMAL_QUEUE);
1360 else
1361 ret = beamforming_send_vht_ndpa_packet(dm, RA, entry->aid, BW, NORMAL_QUEUE);
1362
1363 if (ret == false) {
1364 beamforming_leave(dm, RA);
1365 entry->is_beamforming_in_progress = false;
1366 return false;
1367 }
1368
1369 PHYDM_DBG(dm, DBG_TXBF, "%s idx %d\n", __func__, idx);
1370 return true;
1371 }
1372
1373 boolean
beamforming_start_sw(void * dm_void,u8 idx,u8 mode,enum channel_width BW)1374 beamforming_start_sw(
1375 void *dm_void,
1376 u8 idx,
1377 u8 mode,
1378 enum channel_width BW)
1379 {
1380 u8 *ra = NULL;
1381 struct dm_struct *dm = (struct dm_struct *)dm_void;
1382 struct _RT_BEAMFORMEE_ENTRY *entry;
1383 boolean ret = true;
1384 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1385 #ifdef SUPPORT_MU_BF
1386 #if (SUPPORT_MU_BF == 1)
1387 u8 i, poll_sta_cnt = 0;
1388 boolean is_get_first_bfee = false;
1389 #endif
1390 #endif
1391
1392 if (beam_info->is_mu_sounding) {
1393 beam_info->is_mu_sounding_in_progress = true;
1394 entry = &beam_info->beamformee_entry[idx];
1395 ra = entry->mac_addr;
1396
1397 } else {
1398 entry = &beam_info->beamformee_entry[idx];
1399
1400 if (entry->is_used == false) {
1401 PHYDM_DBG(dm, DBG_TXBF,
1402 "Skip Beamforming, no entry for idx =%d\n",
1403 idx);
1404 entry->is_beamforming_in_progress = false;
1405 return false;
1406 }
1407
1408 if (entry->is_beamforming_in_progress) {
1409 PHYDM_DBG(dm, DBG_TXBF,
1410 "is_beamforming_in_progress, skip...\n");
1411 return false;
1412 }
1413
1414 entry->is_beamforming_in_progress = true;
1415 ra = entry->mac_addr;
1416
1417 if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_AUTO_HT_TIMER) {
1418 if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)) {
1419 entry->is_beamforming_in_progress = false;
1420 PHYDM_DBG(dm, DBG_TXBF,
1421 "%s Return by not support BEAMFORMER_CAP_HT_EXPLICIT <==\n",
1422 __func__);
1423 return false;
1424 }
1425 } else if (mode == SOUNDING_SW_VHT_TIMER || mode == SOUNDING_HW_VHT_TIMER || mode == SOUNDING_AUTO_VHT_TIMER) {
1426 if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)) {
1427 entry->is_beamforming_in_progress = false;
1428 PHYDM_DBG(dm, DBG_TXBF,
1429 "%s Return by not support BEAMFORMER_CAP_VHT_SU <==\n",
1430 __func__);
1431 return false;
1432 }
1433 }
1434 if (entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED && entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
1435 entry->is_beamforming_in_progress = false;
1436 PHYDM_DBG(dm, DBG_TXBF,
1437 "%s Return by incorrect beamform_entry_state(%d) <==\n",
1438 __func__, entry->beamform_entry_state);
1439 return false;
1440 } else {
1441 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
1442 entry->is_sound = true;
1443 }
1444
1445 beam_info->beamformee_cur_idx = idx;
1446 }
1447
1448 /*@2014.12.22 Luke: Need to be checked*/
1449 /*@GET_TXBF_INFO(adapter)->fTxbfSet(adapter, TXBF_SET_SOUNDING_STATUS, (u8*)&idx);*/
1450
1451 if (mode == SOUNDING_SW_HT_TIMER || mode == SOUNDING_HW_HT_TIMER || mode == SOUNDING_AUTO_HT_TIMER)
1452 ret = beamforming_send_ht_ndpa_packet(dm, ra, BW, NORMAL_QUEUE);
1453 else
1454 ret = beamforming_send_vht_ndpa_packet(dm, ra, entry->aid, BW, NORMAL_QUEUE);
1455
1456 if (ret == false) {
1457 beamforming_leave(dm, ra);
1458 entry->is_beamforming_in_progress = false;
1459 return false;
1460 }
1461
1462 /*@--------------------------
1463 * Send BF Report Poll for MU BF
1464 --------------------------*/
1465 #ifdef SUPPORT_MU_BF
1466 #if (SUPPORT_MU_BF == 1)
1467 if (beam_info->beamformee_mu_cnt <= 1)
1468 goto out;
1469
1470 /* @More than 1 MU STA*/
1471 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
1472 entry = &beam_info->beamformee_entry[i];
1473 if (!entry->is_mu_sta)
1474 continue;
1475
1476 if (!is_get_first_bfee) {
1477 is_get_first_bfee = true;
1478 continue;
1479 }
1480
1481 poll_sta_cnt++;
1482 if (poll_sta_cnt == (beam_info->beamformee_mu_cnt - 1)) /* The last STA*/
1483 send_sw_vht_bf_report_poll(dm, entry->mac_addr, true);
1484 else
1485 send_sw_vht_bf_report_poll(dm, entry->mac_addr, false);
1486 }
1487 out:
1488 #endif
1489 #endif
1490 return true;
1491 }
1492
1493 boolean
beamforming_start_fw(void * dm_void,u8 idx)1494 beamforming_start_fw(
1495 void *dm_void,
1496 u8 idx)
1497 {
1498 struct dm_struct *dm = (struct dm_struct *)dm_void;
1499 struct _RT_BEAMFORMEE_ENTRY *entry;
1500 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1501
1502 entry = &beam_info->beamformee_entry[idx];
1503 if (entry->is_used == false) {
1504 PHYDM_DBG(dm, DBG_TXBF,
1505 "Skip Beamforming, no entry for idx =%d\n", idx);
1506 return false;
1507 }
1508
1509 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
1510 entry->is_sound = true;
1511 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);
1512
1513 PHYDM_DBG(dm, DBG_TXBF, "[%s] End, idx=0x%X\n", __func__, idx);
1514 return true;
1515 }
1516
beamforming_check_sounding_success(void * dm_void,boolean status)1517 void beamforming_check_sounding_success(
1518 void *dm_void,
1519 boolean status)
1520 {
1521 struct dm_struct *dm = (struct dm_struct *)dm_void;
1522 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1523 struct _RT_BEAMFORMEE_ENTRY *entry = &beam_info->beamformee_entry[beam_info->beamformee_cur_idx];
1524
1525 PHYDM_DBG(dm, DBG_TXBF, "[David]@%s Start!\n", __func__);
1526
1527 if (status == 1) {
1528 if (entry->log_status_fail_cnt == 21)
1529 beamforming_dym_period(dm, status);
1530 entry->log_status_fail_cnt = 0;
1531 } else if (entry->log_status_fail_cnt <= 20) {
1532 entry->log_status_fail_cnt++;
1533 PHYDM_DBG(dm, DBG_TXBF, "%s log_status_fail_cnt %d\n", __func__,
1534 entry->log_status_fail_cnt);
1535 }
1536 if (entry->log_status_fail_cnt > 20) {
1537 entry->log_status_fail_cnt = 21;
1538 PHYDM_DBG(dm, DBG_TXBF,
1539 "%s log_status_fail_cnt > 20, Stop SOUNDING\n",
1540 __func__);
1541 beamforming_dym_period(dm, status);
1542 }
1543 }
1544
phydm_beamforming_end_sw(void * dm_void,boolean status)1545 void phydm_beamforming_end_sw(
1546 void *dm_void,
1547 boolean status)
1548 {
1549 struct dm_struct *dm = (struct dm_struct *)dm_void;
1550 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1551 struct _RT_BEAMFORMEE_ENTRY *entry = &beam_info->beamformee_entry[beam_info->beamformee_cur_idx];
1552
1553 if (beam_info->is_mu_sounding) {
1554 PHYDM_DBG(dm, DBG_TXBF, "%s: MU sounding done\n", __func__);
1555 beam_info->is_mu_sounding_in_progress = false;
1556 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS,
1557 (u8 *)&beam_info->beamformee_cur_idx);
1558 } else {
1559 if (entry->beamform_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSING) {
1560 PHYDM_DBG(dm, DBG_TXBF, "[%s] BeamformStatus %d\n",
1561 __func__, entry->beamform_entry_state);
1562 return;
1563 }
1564
1565 if (beam_info->tx_bf_data_rate >= ODM_RATEVHTSS3MCS7 && beam_info->tx_bf_data_rate <= ODM_RATEVHTSS3MCS9 && !beam_info->snding3ss) {
1566 PHYDM_DBG(dm, DBG_TXBF,
1567 "[%s] VHT3SS 7,8,9, do not apply V matrix.\n",
1568 __func__);
1569 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
1570 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS,
1571 (u8 *)&beam_info->beamformee_cur_idx);
1572 } else if (status == 1) {
1573 entry->log_status_fail_cnt = 0;
1574 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSED;
1575 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_STATUS,
1576 (u8 *)&beam_info->beamformee_cur_idx);
1577 } else {
1578 entry->log_status_fail_cnt++;
1579 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
1580 hal_com_txbf_set(dm, TXBF_SET_TX_PATH_RESET,
1581 (u8 *)&beam_info->beamformee_cur_idx);
1582 PHYDM_DBG(dm, DBG_TXBF, "[%s] log_status_fail_cnt %d\n",
1583 __func__, entry->log_status_fail_cnt);
1584 }
1585
1586 if (entry->log_status_fail_cnt > 50) {
1587 PHYDM_DBG(dm, DBG_TXBF,
1588 "%s log_status_fail_cnt > 50, Stop SOUNDING\n",
1589 __func__);
1590 entry->is_sound = false;
1591 beamforming_deinit_entry(dm, entry->mac_addr);
1592
1593 /*@Modified by David - Every action of deleting entry should follow by Notify*/
1594 phydm_beamforming_notify(dm);
1595 }
1596
1597 entry->is_beamforming_in_progress = false;
1598 }
1599 PHYDM_DBG(dm, DBG_TXBF, "%s: status=%d\n", __func__, status);
1600 }
1601
beamforming_timer_callback(void * dm_void)1602 void beamforming_timer_callback(
1603 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1604 void *dm_void
1605 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1606 void *context
1607 #endif
1608 )
1609 {
1610 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1611 struct dm_struct *dm = (struct dm_struct *)dm_void;
1612 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1613 void *adapter = (void *)context;
1614 PHAL_DATA_TYPE hal_data = GET_HAL_DATA(((PADAPTER)adapter));
1615 struct dm_struct *dm = &hal_data->odmpriv;
1616 #endif
1617 boolean ret = false;
1618 struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
1619 struct _RT_BEAMFORMEE_ENTRY *entry = &(beam_info->beamformee_entry[beam_info->beamformee_cur_idx]);
1620 struct _RT_SOUNDING_INFO *sound_info = &(beam_info->sounding_info);
1621 boolean is_beamforming_in_progress;
1622
1623 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1624
1625 if (beam_info->is_mu_sounding)
1626 is_beamforming_in_progress = beam_info->is_mu_sounding_in_progress;
1627 else
1628 is_beamforming_in_progress = entry->is_beamforming_in_progress;
1629
1630 if (is_beamforming_in_progress) {
1631 PHYDM_DBG(dm, DBG_TXBF,
1632 "is_beamforming_in_progress, reset it\n");
1633 phydm_beamforming_end_sw(dm, 0);
1634 }
1635
1636 ret = phydm_beamforming_select_beam_entry(dm, beam_info);
1637 #if (SUPPORT_MU_BF == 1)
1638 if (ret && beam_info->beamformee_mu_cnt > 1)
1639 ret = 1;
1640 else
1641 ret = 0;
1642 #endif
1643 if (ret)
1644 ret = beamforming_start_sw(dm, sound_info->sound_idx, sound_info->sound_mode, sound_info->sound_bw);
1645 else
1646 PHYDM_DBG(dm, DBG_TXBF,
1647 "%s, Error value return from BeamformingStart_V2\n",
1648 __func__);
1649
1650 if (beam_info->beamformee_su_cnt != 0 || beam_info->beamformee_mu_cnt > 1) {
1651 if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER)
1652 odm_set_timer(dm, &beam_info->beamforming_timer, sound_info->sound_period);
1653 else {
1654 u32 val = (sound_info->sound_period << 16) | HAL_TIMER_TXBF;
1655 phydm_set_hw_reg_handler_interface(dm, HW_VAR_HW_REG_TIMER_RESTART, (u8 *)(&val));
1656 }
1657 }
1658 }
1659
beamforming_sw_timer_callback(struct phydm_timer_list * timer)1660 void beamforming_sw_timer_callback(
1661 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1662 struct phydm_timer_list *timer
1663 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1664 void *function_context
1665 #endif
1666 )
1667 {
1668 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1669 void *adapter = (void *)timer->Adapter;
1670 HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));
1671 struct dm_struct *dm = &hal_data->DM_OutSrc;
1672
1673 PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
1674 beamforming_timer_callback(dm);
1675 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1676 struct dm_struct *dm = (struct dm_struct *)function_context;
1677 void *adapter = dm->adapter;
1678
1679 if (*dm->is_net_closed == true)
1680 return;
1681 phydm_run_in_thread_cmd(dm, beamforming_timer_callback, adapter);
1682 #endif
1683 }
1684
phydm_beamforming_init(void * dm_void)1685 void phydm_beamforming_init(
1686 void *dm_void)
1687 {
1688 struct dm_struct *dm = (struct dm_struct *)dm_void;
1689 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1690 struct _RT_BEAMFORMING_OID_INFO *beam_oid_info = &beam_info->beamforming_oid_info;
1691 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1692 void *adapter = dm->adapter;
1693 HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));
1694
1695 #ifdef BEAMFORMING_VERSION_1
1696 if (hal_data->beamforming_version != BEAMFORMING_VERSION_1) {
1697 return;
1698 }
1699 #endif
1700 #endif
1701
1702 beam_oid_info->sound_oid_mode = SOUNDING_STOP_OID_TIMER;
1703 PHYDM_DBG(dm, DBG_TXBF, "%s mode (%d)\n", __func__,
1704 beam_oid_info->sound_oid_mode);
1705
1706 beam_info->beamformee_su_cnt = 0;
1707 beam_info->beamformer_su_cnt = 0;
1708 beam_info->beamformee_mu_cnt = 0;
1709 beam_info->beamformer_mu_cnt = 0;
1710 beam_info->beamformee_mu_reg_maping = 0;
1711 beam_info->mu_ap_index = 0;
1712 beam_info->is_mu_sounding = false;
1713 beam_info->first_mu_bfee_index = 0xFF;
1714 beam_info->apply_v_matrix = true;
1715 beam_info->snding3ss = false;
1716
1717 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1718 beam_info->source_adapter = dm->adapter;
1719 #endif
1720 hal_com_txbf_beamform_init(dm);
1721 }
1722
1723 boolean
phydm_acting_determine(void * dm_void,enum phydm_acting_type type)1724 phydm_acting_determine(
1725 void *dm_void,
1726 enum phydm_acting_type type)
1727 {
1728 struct dm_struct *dm = (struct dm_struct *)dm_void;
1729 boolean ret = false;
1730 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1731 void *adapter = dm->beamforming_info.source_adapter;
1732 #else
1733 struct _ADAPTER *adapter = dm->adapter;
1734 #endif
1735
1736 #if (DM_ODM_SUPPORT_TYPE & ODM_WIN)
1737 if (type == phydm_acting_as_ap)
1738 ret = ACTING_AS_AP(adapter);
1739 else if (type == phydm_acting_as_ibss)
1740 ret = ACTING_AS_IBSS(((PADAPTER)(adapter)));
1741 #elif (DM_ODM_SUPPORT_TYPE & ODM_CE)
1742 struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
1743
1744 if (type == phydm_acting_as_ap)
1745 ret = check_fwstate(pmlmepriv, WIFI_AP_STATE);
1746 else if (type == phydm_acting_as_ibss)
1747 ret = check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
1748 #endif
1749
1750 return ret;
1751 }
1752
beamforming_enter(void * dm_void,u16 sta_idx,u8 * my_mac_addr)1753 void beamforming_enter(void *dm_void, u16 sta_idx, u8 *my_mac_addr)
1754 {
1755 struct dm_struct *dm = (struct dm_struct *)dm_void;
1756 u8 bfer_bfee_idx = 0xff;
1757
1758 if (beamforming_init_entry(dm, sta_idx, &bfer_bfee_idx, my_mac_addr))
1759 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_ENTER, (u8 *)&bfer_bfee_idx);
1760
1761 PHYDM_DBG(dm, DBG_TXBF, "[%s] End!\n", __func__);
1762 }
1763
beamforming_leave(void * dm_void,u8 * RA)1764 void beamforming_leave(
1765 void *dm_void,
1766 u8 *RA)
1767 {
1768 struct dm_struct *dm = (struct dm_struct *)dm_void;
1769
1770 if (RA != NULL) {
1771 beamforming_deinit_entry(dm, RA);
1772 phydm_beamforming_notify(dm);
1773 }
1774
1775 PHYDM_DBG(dm, DBG_TXBF, "[%s] End!!\n", __func__);
1776 }
1777
1778 enum beamforming_cap
phydm_beamforming_get_beam_cap(void * dm_void,struct _RT_BEAMFORMING_INFO * beam_info)1779 phydm_beamforming_get_beam_cap(
1780 void *dm_void,
1781 struct _RT_BEAMFORMING_INFO *beam_info)
1782 {
1783 u8 i;
1784 boolean is_self_beamformer = false;
1785 boolean is_self_beamformee = false;
1786 struct _RT_BEAMFORMEE_ENTRY beamformee_entry;
1787 struct _RT_BEAMFORMER_ENTRY beamformer_entry;
1788 enum beamforming_cap beamform_cap = BEAMFORMING_CAP_NONE;
1789 struct dm_struct *dm = (struct dm_struct *)dm_void;
1790
1791 PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
1792
1793 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
1794 beamformee_entry = beam_info->beamformee_entry[i];
1795
1796 if (beamformee_entry.is_used) {
1797 is_self_beamformer = true;
1798 PHYDM_DBG(dm, DBG_TXBF,
1799 "[%s] BFee entry %d is_used=true\n", __func__,
1800 i);
1801 break;
1802 }
1803 }
1804
1805 for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
1806 beamformer_entry = beam_info->beamformer_entry[i];
1807
1808 if (beamformer_entry.is_used) {
1809 is_self_beamformee = true;
1810 PHYDM_DBG(dm, DBG_TXBF,
1811 "[%s]: BFer entry %d is_used=true\n",
1812 __func__, i);
1813 break;
1814 }
1815 }
1816
1817 if (is_self_beamformer)
1818 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMER_CAP);
1819 if (is_self_beamformee)
1820 beamform_cap = (enum beamforming_cap)(beamform_cap | BEAMFORMEE_CAP);
1821
1822 return beamform_cap;
1823 }
1824
1825 boolean
beamforming_control_v1(void * dm_void,u8 * RA,u8 AID,u8 mode,enum channel_width BW,u8 rate)1826 beamforming_control_v1(
1827 void *dm_void,
1828 u8 *RA,
1829 u8 AID,
1830 u8 mode,
1831 enum channel_width BW,
1832 u8 rate)
1833 {
1834 struct dm_struct *dm = (struct dm_struct *)dm_void;
1835 boolean ret = true;
1836
1837 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1838
1839 PHYDM_DBG(dm, DBG_TXBF, "AID (%d), mode (%d), BW (%d)\n", AID, mode,
1840 BW);
1841
1842 switch (mode) {
1843 case 0:
1844 ret = beamforming_start_v1(dm, RA, 0, BW, rate);
1845 break;
1846 case 1:
1847 ret = beamforming_start_v1(dm, RA, 1, BW, rate);
1848 break;
1849 case 2:
1850 phydm_beamforming_ndpa_rate(dm, BW, rate);
1851 ret = beamforming_send_vht_ndpa_packet(dm, RA, AID, BW, NORMAL_QUEUE);
1852 break;
1853 case 3:
1854 phydm_beamforming_ndpa_rate(dm, BW, rate);
1855 ret = beamforming_send_ht_ndpa_packet(dm, RA, BW, NORMAL_QUEUE);
1856 break;
1857 }
1858 return ret;
1859 }
1860
1861 /*Only OID uses this function*/
1862 boolean
phydm_beamforming_control_v2(void * dm_void,u8 idx,u8 mode,enum channel_width BW,u16 period)1863 phydm_beamforming_control_v2(
1864 void *dm_void,
1865 u8 idx,
1866 u8 mode,
1867 enum channel_width BW,
1868 u16 period)
1869 {
1870 struct dm_struct *dm = (struct dm_struct *)dm_void;
1871 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1872 struct _RT_BEAMFORMING_OID_INFO *beam_oid_info = &beam_info->beamforming_oid_info;
1873
1874 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1875 PHYDM_DBG(dm, DBG_TXBF, "idx (%d), mode (%d), BW (%d), period (%d)\n",
1876 idx, mode, BW, period);
1877
1878 beam_oid_info->sound_oid_idx = idx;
1879 beam_oid_info->sound_oid_mode = (enum sounding_mode)mode;
1880 beam_oid_info->sound_oid_bw = BW;
1881 beam_oid_info->sound_oid_period = period;
1882
1883 phydm_beamforming_notify(dm);
1884
1885 return true;
1886 }
1887
phydm_beamforming_watchdog(void * dm_void)1888 void phydm_beamforming_watchdog(
1889 void *dm_void)
1890 {
1891 struct dm_struct *dm = (struct dm_struct *)dm_void;
1892 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1893
1894 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1895
1896 if (beam_info->beamformee_su_cnt == 0)
1897 return;
1898
1899 beamforming_dym_period(dm, 0);
1900 }
1901 enum beamforming_cap
phydm_get_beamform_cap(void * dm_void)1902 phydm_get_beamform_cap(
1903 void *dm_void)
1904 {
1905 struct dm_struct *dm = (struct dm_struct *)dm_void;
1906 struct cmn_sta_info *sta = NULL;
1907 struct bf_cmn_info *bf_info = NULL;
1908 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1909 void *adapter = dm->adapter;
1910 enum beamforming_cap beamform_cap = BEAMFORMING_CAP_NONE;
1911 u8 macid;
1912 u8 ht_curbeamformcap = 0;
1913 u16 vht_curbeamformcap = 0;
1914
1915 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1916 PMGNT_INFO p_MgntInfo = &(((PADAPTER)(adapter))->MgntInfo);
1917 PRT_VERY_HIGH_THROUGHPUT p_vht_info = GET_VHT_INFO(p_MgntInfo);
1918 PRT_HIGH_THROUGHPUT p_ht_info = GET_HT_INFO(p_MgntInfo);
1919
1920 ht_curbeamformcap = p_ht_info->HtCurBeamform;
1921 vht_curbeamformcap = p_vht_info->VhtCurBeamform;
1922
1923 PHYDM_DBG(dm, DBG_ANT_DIV,
1924 "[%s] WIN ht_curcap = %d ; vht_curcap = %d\n", __func__,
1925 ht_curbeamformcap, vht_curbeamformcap);
1926
1927 if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) /*We are Beamformee because the STA is Beamformer*/
1928 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_HT_EXPLICIT | BEAMFORMEE_CAP));
1929
1930 /*We are Beamformer because the STA is Beamformee*/
1931 if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMEE_ENABLE))
1932 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP));
1933
1934 #if (ODM_IC_11AC_SERIES_SUPPORT == 1)
1935
1936 /* We are Beamformee because the STA is SU Beamformer*/
1937 if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMER_ENABLE))
1938 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP));
1939
1940 /* We are Beamformer because the STA is SU Beamformee*/
1941 if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE))
1942 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP));
1943
1944 /* We are Beamformee because the STA is MU Beamformer*/
1945 if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE))
1946 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_MU | BEAMFORMEE_CAP));
1947 #endif
1948 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1949
1950 for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++) {
1951 sta = dm->phydm_sta_info[macid];
1952
1953 if (!is_sta_active(sta))
1954 continue;
1955
1956 bf_info = &sta->bf_info;
1957 vht_curbeamformcap = bf_info->vht_beamform_cap;
1958 ht_curbeamformcap = bf_info->ht_beamform_cap;
1959
1960 if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) /*We are Beamformee because the STA is Beamformer*/
1961 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_HT_EXPLICIT | BEAMFORMEE_CAP));
1962
1963 /*We are Beamformer because the STA is Beamformee*/
1964 if (TEST_FLAG(ht_curbeamformcap, BEAMFORMING_HT_BEAMFORMEE_ENABLE))
1965 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP));
1966
1967 #if (ODM_IC_11AC_SERIES_SUPPORT == 1)
1968 /* We are Beamformee because the STA is SU Beamformer*/
1969 if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMER_ENABLE))
1970 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_SU | BEAMFORMEE_CAP));
1971
1972 /* We are Beamformer because the STA is SU Beamformee*/
1973 if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE))
1974 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMER_CAP_VHT_SU | BEAMFORMER_CAP));
1975
1976 /* We are Beamformee because the STA is MU Beamformer*/
1977 if (TEST_FLAG(vht_curbeamformcap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE))
1978 beamform_cap = (enum beamforming_cap)(beamform_cap | (BEAMFORMEE_CAP_VHT_MU | BEAMFORMEE_CAP));
1979 #endif
1980 }
1981 PHYDM_DBG(dm, DBG_ANT_DIV, "[%s] CE ht_curcap = %d ; vht_curcap = %d\n",
1982 __func__, ht_curbeamformcap, vht_curbeamformcap);
1983
1984 #endif
1985
1986 return beamform_cap;
1987 }
1988
1989 #endif
1990