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