OSDN Git Service

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