1 /******************************************************************************
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
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.
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
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
26 #include "mp_precomp.h"
27 #include "phydm_precomp.h"
29 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
30 #if WPP_SOFTWARE_TRACE
31 #include "phydm_beamforming.tmh"
35 #if (BEAMFORMING_SUPPORT == 1)
37 void phydm_get_txbf_device_num(
41 #if (defined(CONFIG_PHYDM_ANTENNA_DIVERSITY)) /*@For BDC*/
42 #if (DM_ODM_SUPPORT_TYPE == ODM_AP)
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;
51 if (is_sta_active(sta)) {
54 PHYDM_DBG(dm, DBG_TXBF, "[Warning] %s invalid sta_info\n",
59 if (sta->support_wireless_set & WIRELESS_VHT) {
60 if (bf->vht_beamform_cap & BEAMFORMING_VHT_BEAMFORMEE_ENABLE)
63 if (bf->vht_beamform_cap & BEAMFORMING_VHT_BEAMFORMER_ENABLE)
66 } else if (sta->support_wireless_set & WIRELESS_HT) {
67 if (bf->ht_beamform_cap & BEAMFORMING_HT_BEAMFORMEE_ENABLE)
70 if (bf->ht_beamform_cap & BEAMFORMING_HT_BEAMFORMER_ENABLE)
75 { /* Our Device act as BFer */
76 dm_bdc_table->w_bfee_client[macid] = true;
77 dm_bdc_table->num_txbfee_client++;
80 dm_bdc_table->w_bfee_client[macid] = false;
83 { /* Our Device act as BFee */
84 dm_bdc_table->w_bfer_client[macid] = true;
85 dm_bdc_table->num_txbfer_client++;
88 dm_bdc_table->w_bfer_client[macid] = false;
94 struct _RT_BEAMFORM_STAINFO *
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);
111 if (!is_sta_active(cmn_sta)) {
112 PHYDM_DBG(dm, DBG_TXBF, "%s => sta_info(mac_id:%d) failed\n",
114 #if (DM_ODM_SUPPORT_TYPE == ODM_CE)
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);
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;
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;
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*/
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;
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);
160 void phydm_sta_info_update(
161 struct dm_struct *dm,
163 struct _RT_BEAMFORMEE_ENTRY *beamform_entry)
165 struct cmn_sta_info *sta = dm->phydm_sta_info[sta_idx];
167 if (!is_sta_active(sta))
170 sta->bf_info.p_aid = beamform_entry->p_aid;
171 sta->bf_info.g_id = beamform_entry->g_id;
174 struct _RT_BEAMFORMEE_ENTRY *
175 phydm_beamforming_get_bfee_entry_by_addr(
180 struct dm_struct *dm = (struct dm_struct *)dm_void;
182 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
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))) {
187 return &beam_info->beamformee_entry[i];
194 struct _RT_BEAMFORMER_ENTRY *
195 phydm_beamforming_get_bfer_entry_by_addr(
200 struct dm_struct *dm = (struct dm_struct *)dm_void;
202 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
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))) {
207 return &beam_info->beamformer_entry[i];
214 struct _RT_BEAMFORMEE_ENTRY *
215 phydm_beamforming_get_entry_by_mac_id(
220 struct dm_struct *dm = (struct dm_struct *)dm_void;
222 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
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) {
227 return &beam_info->beamformee_entry[i];
235 phydm_beamforming_get_entry_beam_cap_by_mac_id(
239 struct dm_struct *dm = (struct dm_struct *)dm_void;
241 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
242 enum beamforming_cap beamform_entry_cap = BEAMFORMING_CAP_NONE;
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;
251 return beamform_entry_cap;
254 struct _RT_BEAMFORMEE_ENTRY *
255 phydm_beamforming_get_free_bfee_entry(
259 struct dm_struct *dm = (struct dm_struct *)dm_void;
261 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
263 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
264 if (beam_info->beamformee_entry[i].is_used == false) {
266 return &beam_info->beamformee_entry[i];
272 struct _RT_BEAMFORMER_ENTRY *
273 phydm_beamforming_get_free_bfer_entry(
277 struct dm_struct *dm = (struct dm_struct *)dm_void;
279 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
281 PHYDM_DBG(dm, DBG_TXBF, "%s ===>\n", __func__);
283 for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
284 if (beam_info->beamformer_entry[i].is_used == false) {
286 return &beam_info->beamformer_entry[i];
293 * Description: Get the first entry index of MU Beamformee.
295 * Return value: index of the first MU sta.
297 * 2015.05.25. Created by tynli.
300 u8 phydm_beamforming_get_first_mu_bfee_entry_idx(
303 struct dm_struct *dm = (struct dm_struct *)dm_void;
305 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
306 boolean is_found = false;
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__,
323 /*@Add SU BFee and MU BFee*/
324 struct _RT_BEAMFORMEE_ENTRY *
325 beamforming_add_bfee_entry(
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,
333 struct dm_struct *dm = (struct dm_struct *)dm_void;
334 struct _RT_BEAMFORMEE_ENTRY *entry = phydm_beamforming_get_free_bfee_entry(dm, idx);
336 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
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);
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;
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)) {
358 PHYDM_DBG(dm, DBG_TXBF, "%s: BFee P_AID as IBSS=%d\n",
359 __func__, entry->p_aid);
362 entry->p_aid = sta->ra[5];
364 entry->p_aid = (entry->p_aid << 1) | (sta->ra[4] >> 7);
366 PHYDM_DBG(dm, DBG_TXBF,
367 "%s: BFee P_AID addressed to AP=0x%X\n",
368 __func__, entry->p_aid);
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;
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*/
381 entry->log_status_fail_cnt = 0;
383 entry->num_of_sounding_dim = num_of_sounding_dim;
384 entry->comp_steering_num_of_bfer = comp_steering_num_of_bfer;
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;
400 /*@Add SU BFee and MU BFer*/
401 struct _RT_BEAMFORMER_ENTRY *
402 beamforming_add_bfer_entry(
404 struct _RT_BEAMFORM_STAINFO *sta,
405 enum beamforming_cap beamform_cap,
406 u8 num_of_sounding_dim,
409 struct dm_struct *dm = (struct dm_struct *)dm_void;
410 struct _RT_BEAMFORMER_ENTRY *entry = phydm_beamforming_get_free_bfer_entry(dm, idx);
412 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
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);
421 entry->p_aid = (sta->aid + bssid * 32) & 0x1ff;
423 /*@(dec(A) + dec(B)*32) mod 512*/
424 } else if (phydm_acting_determine(dm, phydm_acting_as_ibss)) {
428 entry->p_aid = sta->ra[5];
430 entry->p_aid = (entry->p_aid << 1) | (sta->ra[4] >> 7);
432 PHYDM_DBG(dm, DBG_TXBF,
433 "%s: P_AID addressed to AP=0x%X\n", __func__,
437 cp_mac_addr(entry->mac_addr, sta->ra);
438 entry->beamform_entry_cap = beamform_cap;
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*/
446 entry->num_of_sounding_dim = num_of_sounding_dim;
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;
464 beamforming_remove_entry(
470 HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));
471 struct dm_struct *dm = &hal_data->DM_OutSrc;
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);
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));
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;
488 if (bfer_entry != NULL) {
489 bfer_entry->is_used = false;
490 bfer_entry->beamform_entry_cap = BEAMFORMING_CAP_NONE;
497 /* Used for beamforming_start_v1 */
498 void phydm_beamforming_ndpa_rate(
500 enum channel_width BW,
503 u16 ndpa_rate = rate;
504 struct dm_struct *dm = (struct dm_struct *)dm_void;
506 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
508 if (ndpa_rate == 0) {
509 if (dm->rssi_min > 30) /* @link RSSI > 30% */
510 ndpa_rate = ODM_RATE24M;
512 ndpa_rate = ODM_RATE6M;
515 if (ndpa_rate < ODM_RATEMCS0)
516 BW = (enum channel_width)CHANNEL_WIDTH_20;
518 ndpa_rate = (ndpa_rate << 8) | BW;
519 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_RATE, (u8 *)&ndpa_rate);
522 /* Used for beamforming_start_sw and beamforming_start_fw */
523 void phydm_beamforming_dym_ndpa_rate(
526 u16 ndpa_rate = ODM_RATE6M, BW;
527 struct dm_struct *dm = (struct dm_struct *)dm_void;
529 ndpa_rate = ODM_RATE6M;
530 BW = CHANNEL_WIDTH_20;
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__,
539 * SW Sounding : SW Timer unit 1ms
540 * HW Timer unit (1/32000) s 32k is clock.
541 * FW Sounding : FW Timer unit 10ms
543 void beamforming_dym_period(
548 boolean is_change_period = false;
549 u16 sound_period_sw, sound_period_fw;
550 struct dm_struct *dm = (struct dm_struct *)dm_void;
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;
556 struct _RT_BEAMFORMEE_ENTRY *entry = &beam_info->beamformee_entry[beam_info->beamformee_cur_idx];
558 PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
560 /* @3 TODO per-client throughput caculation. */
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 */
566 sound_period_sw = 4000; /* @4s */
567 sound_period_fw = 400;
569 PHYDM_DBG(dm, DBG_TXBF, "[%s]sound_period_sw=%d, sound_period_fw=%d\n",
570 __func__, sound_period_sw, sound_period_fw);
572 for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
573 beamform_entry = beam_info->beamformee_entry + idx;
575 if (beamform_entry->default_csi_cnt > 20) {
576 /*@Modified by David*/
577 sound_period_sw = 4000;
578 sound_period_fw = 400;
581 PHYDM_DBG(dm, DBG_TXBF, "[%s] period = %d\n", __func__,
583 if ((beamform_entry->beamform_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) == 0)
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. */
591 } else if (beamform_entry->sound_period != sound_period_sw)
592 beamform_entry->sound_period = sound_period_sw;
595 if (is_change_period)
596 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);
600 beamforming_send_ht_ndpa_packet(
603 enum channel_width BW,
607 struct dm_struct *dm = (struct dm_struct *)dm_void;
609 if (q_idx == BEACON_QUEUE)
610 ret = send_fw_ht_ndpa_packet(dm, RA, BW);
612 ret = send_sw_ht_ndpa_packet(dm, RA, BW);
618 beamforming_send_vht_ndpa_packet(
622 enum channel_width BW,
625 struct dm_struct *dm = (struct dm_struct *)dm_void;
626 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
629 hal_com_txbf_set(dm, TXBF_SET_GET_TX_RATE, NULL);
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",
636 if (q_idx == BEACON_QUEUE) /* Send to reserved page => FW NDPA */
637 ret = send_fw_vht_ndpa_packet(dm, RA, AID, BW);
640 #if (SUPPORT_MU_BF == 1)
641 beam_info->is_mu_sounding = true;
642 ret = send_sw_vht_mu_ndpa_packet(dm, BW);
644 beam_info->is_mu_sounding = false;
645 ret = send_sw_vht_ndpa_packet(dm, RA, AID, BW);
648 beam_info->is_mu_sounding = false;
649 ret = send_sw_vht_ndpa_packet(dm, RA, AID, BW);
656 enum beamforming_notify_state
657 phydm_beamfomring_is_sounding(
659 struct _RT_BEAMFORMING_INFO *beam_info,
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;
667 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
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;
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",
685 if (beam_info->beamformee_entry[i].is_mu_sta)
686 is_sounding = BEAMFORMEE_NOTIFY_ADD_MU;
688 is_sounding = BEAMFORMEE_NOTIFY_ADD_SU;
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",
695 if (beam_info->beamformee_entry[i].is_mu_sta)
696 is_sounding = BEAMFORMEE_NOTIFY_DELETE_MU;
698 is_sounding = BEAMFORMEE_NOTIFY_DELETE_SU;
703 PHYDM_DBG(dm, DBG_TXBF, "%s End, is_sounding = %d\n", __func__,
708 /* This function is unused */
709 u8 phydm_beamforming_sounding_idx(
711 struct _RT_BEAMFORMING_INFO *beam_info)
714 struct _RT_BEAMFORMING_OID_INFO beam_oid_info = beam_info->beamforming_oid_info;
715 struct dm_struct *dm = (struct dm_struct *)dm_void;
717 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
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;
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) {
736 phydm_beamforming_sounding_mode(
738 struct _RT_BEAMFORMING_INFO *beam_info,
741 struct dm_struct *dm = (struct dm_struct *)dm_void;
742 u8 support_interface = dm->support_interface;
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;
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;
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;
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;
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;
767 mode = SOUNDING_SW_HT_TIMER;
769 mode = sounding_stop_all_timer;
771 PHYDM_DBG(dm, DBG_TXBF, "[%s] support_interface=%d, mode=%d\n",
772 __func__, support_interface, mode);
777 u16 phydm_beamforming_sounding_time(
779 struct _RT_BEAMFORMING_INFO *beam_info,
780 enum sounding_mode mode,
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;
788 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
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;*/
796 sounding_time = beam_entry.sound_period;
798 return sounding_time;
802 phydm_beamforming_sounding_bw(
804 struct _RT_BEAMFORMING_INFO *beam_info,
805 enum sounding_mode mode,
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;
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;*/
819 sounding_bw = beam_entry.sound_bw;
821 PHYDM_DBG(dm, DBG_TXBF, "%s, sounding_bw=0x%X\n", __func__,
828 phydm_beamforming_select_beam_entry(
830 struct _RT_BEAMFORMING_INFO *beam_info)
832 struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;
833 struct dm_struct *dm = (struct dm_struct *)dm_void;
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;*/
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);
843 sound_info->sound_mode = sounding_stop_all_timer;
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",
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);
857 /*SU BFee Entry Only*/
859 phydm_beamforming_start_period(
862 struct dm_struct *dm = (struct dm_struct *)dm_void;
864 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
865 struct _RT_SOUNDING_INFO *sound_info = &beam_info->sounding_info;
867 phydm_beamforming_dym_ndpa_rate(dm);
869 phydm_beamforming_select_beam_entry(dm, beam_info); /* @Modified */
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));
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);
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);
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(
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;
911 HAL_HW_TIMER_TYPE timer_type = HAL_TIMER_TXBF;
913 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
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);*/
924 void phydm_beamforming_end_period_fw(
927 struct dm_struct *dm = (struct dm_struct *)dm_void;
930 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_FW_NDPA, (u8 *)&idx);
931 PHYDM_DBG(dm, DBG_TXBF, "[%s]\n", __func__);
934 /*SU BFee Entry Only*/
935 void phydm_beamforming_clear_entry_sw(
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;
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",
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);
965 beamform_entry->is_sound = false;
969 for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
970 beamform_entry = beam_info->beamformee_entry + idx;
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.*/
976 if (!beamform_entry->is_sound)
979 PHYDM_DBG(dm, DBG_TXBF, "[%s] SW reset BFee entry %d\n",
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.
986 * 2. After C2H packet, then reset state to initialized and clear status bit.
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);
996 beamform_entry->is_sound = false;
1000 void phydm_beamforming_clear_entry_fw(
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;
1011 if (delete_idx < BEAMFORMEE_ENTRY_NUM) {
1012 beamform_entry = beam_info->beamformee_entry + delete_idx;
1014 if (!(!beamform_entry->is_used && beamform_entry->is_sound)) {
1015 PHYDM_DBG(dm, DBG_TXBF,
1016 "[%s] FW delete_idx is wrong!!!!!\n",
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;
1026 for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
1027 beamform_entry = beam_info->beamformee_entry + idx;
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.*/
1033 if (beamform_entry->is_sound) {
1034 PHYDM_DBG(dm, DBG_TXBF,
1035 "[%s]FW reset BFee entry %d\n",
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.
1042 * 2. After C2H packet, then reset state to initialized and clear status bit.
1045 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
1046 beamform_entry->is_sound = false;
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
1058 void phydm_beamforming_notify(
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;
1067 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1069 is_sounding = phydm_beamfomring_is_sounding(dm, beam_info, &idx);
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);
1076 switch (is_sounding) {
1077 case BEAMFORMEE_NOTIFY_ADD_SU:
1078 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_ADD_SU\n",
1080 phydm_beamforming_start_period(dm);
1083 case BEAMFORMEE_NOTIFY_DELETE_SU:
1084 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_DELETE_SU\n",
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",
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",
1103 case BEAMFORMEE_NOTIFY_ADD_MU:
1104 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_ADD_MU\n",
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*/
1111 PHYDM_DBG(dm, DBG_TXBF,
1112 "%s: Less or larger than 2 MU STAs, not to set timer\n",
1116 case BEAMFORMEE_NOTIFY_DELETE_MU:
1117 PHYDM_DBG(dm, DBG_TXBF, "%s: BEAMFORMEE_NOTIFY_DELETE_MU\n",
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",
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);
1134 phydm_beamforming_clear_entry_sw(dm, false, idx);
1135 phydm_beamforming_end_period_sw(dm);
1146 beamforming_init_entry(
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;
1160 if (!is_sta_active(cmn_sta)) {
1161 PHYDM_DBG(dm, DBG_TXBF, "%s => sta_info(mac_id:%d) failed\n",
1163 #if (DM_ODM_SUPPORT_TYPE == ODM_CE)
1169 sta = phydm_sta_info_init(dm, sta_idx);
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");
1178 if (!(cmn_sta->support_wireless_set & (WIRELESS_VHT | WIRELESS_HT)))
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;
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;
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);
1200 #if (ODM_IC_11AC_SERIES_SUPPORT == 1)
1201 if (cmn_sta->support_wireless_set & WIRELESS_VHT) { /*VHT*/
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;
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;
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;
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;
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,
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);
1239 if (beamform_cap == BEAMFORMING_CAP_NONE)
1242 PHYDM_DBG(dm, DBG_TXBF, "[%s] Self BF Entry Cap = 0x%02X\n", __func__,
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);
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",
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);
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);
1271 PHYDM_DBG(dm, DBG_TXBF, "[%s]: Add BFee entry %d\n",
1272 __func__, bfee_idx);
1274 if (beamform_entry == NULL)
1277 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
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)
1284 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
1286 beamform_entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
1287 phydm_sta_info_update(dm, sta_idx, beamform_entry);
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);
1298 void beamforming_deinit_entry(
1302 struct dm_struct *dm = (struct dm_struct *)dm_void;
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;
1309 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
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);
1320 dm->beamforming_info.beamformee_su_cnt -= 1;
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;
1331 dm->beamforming_info.beamformer_su_cnt -= 1;
1336 hal_com_txbf_set(dm, TXBF_SET_SOUNDING_LEAVE, (u8 *)&idx);
1338 PHYDM_DBG(dm, DBG_TXBF, "%s End, idx = 0x%X\n", __func__, idx);
1342 beamforming_start_v1(
1346 enum channel_width BW,
1349 struct dm_struct *dm = (struct dm_struct *)dm_void;
1351 struct _RT_BEAMFORMEE_ENTRY *entry;
1353 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1355 entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
1357 if (entry->is_used == false) {
1358 entry->is_beamforming_in_progress = false;
1361 if (entry->is_beamforming_in_progress)
1364 entry->is_beamforming_in_progress = true;
1367 if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)) {
1368 entry->is_beamforming_in_progress = false;
1371 } else if (mode == 0) {
1372 if (!(entry->beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)) {
1373 entry->is_beamforming_in_progress = false;
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;
1382 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
1383 entry->is_sound = true;
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);
1393 ret = beamforming_send_ht_ndpa_packet(dm, RA, BW, NORMAL_QUEUE);
1395 ret = beamforming_send_vht_ndpa_packet(dm, RA, entry->aid, BW, NORMAL_QUEUE);
1398 beamforming_leave(dm, RA);
1399 entry->is_beamforming_in_progress = false;
1403 PHYDM_DBG(dm, DBG_TXBF, "%s idx %d\n", __func__, idx);
1408 beamforming_start_sw(
1412 enum channel_width BW)
1415 struct dm_struct *dm = (struct dm_struct *)dm_void;
1416 struct _RT_BEAMFORMEE_ENTRY *entry;
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;
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;
1432 entry = &beam_info->beamformee_entry[idx];
1434 if (entry->is_used == false) {
1435 PHYDM_DBG(dm, DBG_TXBF,
1436 "Skip Beamforming, no entry for idx =%d\n",
1438 entry->is_beamforming_in_progress = false;
1442 if (entry->is_beamforming_in_progress) {
1443 PHYDM_DBG(dm, DBG_TXBF,
1444 "is_beamforming_in_progress, skip...\n");
1448 entry->is_beamforming_in_progress = true;
1449 ra = entry->mac_addr;
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",
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",
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);
1475 entry->beamform_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
1476 entry->is_sound = true;
1479 beam_info->beamformee_cur_idx = idx;
1482 /*@2014.12.22 Luke: Need to be checked*/
1483 /*@GET_TXBF_INFO(adapter)->fTxbfSet(adapter, TXBF_SET_SOUNDING_STATUS, (u8*)&idx);*/
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);
1488 ret = beamforming_send_vht_ndpa_packet(dm, ra, entry->aid, BW, NORMAL_QUEUE);
1491 beamforming_leave(dm, ra);
1492 entry->is_beamforming_in_progress = false;
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)
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)
1510 if (!is_get_first_bfee) {
1511 is_get_first_bfee = true;
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);
1519 send_sw_vht_bf_report_poll(dm, entry->mac_addr, false);
1528 beamforming_start_fw(
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;
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);
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);
1547 PHYDM_DBG(dm, DBG_TXBF, "[%s] End, idx=0x%X\n", __func__, idx);
1551 void beamforming_check_sounding_success(
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];
1559 PHYDM_DBG(dm, DBG_TXBF, "[David]@%s Start!\n", __func__);
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);
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",
1575 beamforming_dym_period(dm, status);
1579 void phydm_beamforming_end_sw(
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];
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);
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);
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",
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);
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);
1620 if (entry->log_status_fail_cnt > 50) {
1621 PHYDM_DBG(dm, DBG_TXBF,
1622 "%s log_status_fail_cnt > 50, Stop SOUNDING\n",
1624 entry->is_sound = false;
1625 beamforming_deinit_entry(dm, entry->mac_addr);
1627 /*@Modified by David - Every action of deleting entry should follow by Notify*/
1628 phydm_beamforming_notify(dm);
1631 entry->is_beamforming_in_progress = false;
1633 PHYDM_DBG(dm, DBG_TXBF, "%s: status=%d\n", __func__, status);
1636 void beamforming_timer_callback(
1637 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1639 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
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;
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;
1657 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1659 if (beam_info->is_mu_sounding)
1660 is_beamforming_in_progress = beam_info->is_mu_sounding_in_progress;
1662 is_beamforming_in_progress = entry->is_beamforming_in_progress;
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);
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)
1678 ret = beamforming_start_sw(dm, sound_info->sound_idx, sound_info->sound_mode, sound_info->sound_bw);
1680 PHYDM_DBG(dm, DBG_TXBF,
1681 "%s, Error value return from BeamformingStart_V2\n",
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);
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));
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
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;
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;
1713 if (*dm->is_net_closed == true)
1715 phydm_run_in_thread_cmd(dm, beamforming_timer_callback, adapter);
1719 void phydm_beamforming_init(
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));
1729 #ifdef BEAMFORMING_VERSION_1
1730 if (hal_data->beamforming_version != BEAMFORMING_VERSION_1) {
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);
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;
1751 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1752 beam_info->source_adapter = dm->adapter;
1754 hal_com_txbf_beamform_init(dm);
1758 phydm_acting_determine(
1760 enum phydm_acting_type type)
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;
1767 struct _ADAPTER *adapter = dm->adapter;
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;
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);
1787 void beamforming_enter(
1791 struct dm_struct *dm = (struct dm_struct *)dm_void;
1792 u8 bfer_bfee_idx = 0xff;
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);
1797 PHYDM_DBG(dm, DBG_TXBF, "[%s] End!\n", __func__);
1800 void beamforming_leave(
1804 struct dm_struct *dm = (struct dm_struct *)dm_void;
1807 beamforming_deinit_entry(dm, RA);
1808 phydm_beamforming_notify(dm);
1811 PHYDM_DBG(dm, DBG_TXBF, "[%s] End!!\n", __func__);
1815 /* Nobody calls this function */
1817 phydm_beamforming_set_txbf_en(
1823 struct dm_struct *dm = (struct dm_struct *)dm_void;
1825 struct _RT_BEAMFORMEE_ENTRY *entry;
1827 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1829 entry = phydm_beamforming_get_entry_by_mac_id(dm, mac_id, &idx);
1834 entry->is_txbf = is_txbf;
1836 PHYDM_DBG(dm, DBG_TXBF, "%s mac_id %d TxBF %d\n", __func__,
1837 entry->mac_id, entry->is_txbf);
1839 phydm_beamforming_notify(dm);
1843 enum beamforming_cap
1844 phydm_beamforming_get_beam_cap(
1846 struct _RT_BEAMFORMING_INFO *beam_info)
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;
1856 PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
1858 for (i = 0; i < BEAMFORMEE_ENTRY_NUM; i++) {
1859 beamformee_entry = beam_info->beamformee_entry[i];
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__,
1870 for (i = 0; i < BEAMFORMER_ENTRY_NUM; i++) {
1871 beamformer_entry = beam_info->beamformer_entry[i];
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",
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);
1887 return beamform_cap;
1891 beamforming_control_v1(
1896 enum channel_width BW,
1899 struct dm_struct *dm = (struct dm_struct *)dm_void;
1902 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1904 PHYDM_DBG(dm, DBG_TXBF, "AID (%d), mode (%d), BW (%d)\n", AID, mode,
1909 ret = beamforming_start_v1(dm, RA, 0, BW, rate);
1912 ret = beamforming_start_v1(dm, RA, 1, BW, rate);
1915 phydm_beamforming_ndpa_rate(dm, BW, rate);
1916 ret = beamforming_send_vht_ndpa_packet(dm, RA, AID, BW, NORMAL_QUEUE);
1919 phydm_beamforming_ndpa_rate(dm, BW, rate);
1920 ret = beamforming_send_ht_ndpa_packet(dm, RA, BW, NORMAL_QUEUE);
1926 /*Only OID uses this function*/
1928 phydm_beamforming_control_v2(
1932 enum channel_width BW,
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;
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);
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;
1948 phydm_beamforming_notify(dm);
1953 void phydm_beamforming_watchdog(
1956 struct dm_struct *dm = (struct dm_struct *)dm_void;
1957 struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info;
1959 PHYDM_DBG(dm, DBG_TXBF, "%s Start!\n", __func__);
1961 if (beam_info->beamformee_su_cnt == 0)
1964 beamforming_dym_period(dm, 0);
1966 enum beamforming_cap
1967 phydm_get_beamform_cap(
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;
1977 u8 ht_curbeamformcap = 0;
1978 u16 vht_curbeamformcap = 0;
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);
1985 ht_curbeamformcap = p_ht_info->HtCurBeamform;
1986 vht_curbeamformcap = p_vht_info->VhtCurBeamform;
1988 PHYDM_DBG(dm, DBG_ANT_DIV,
1989 "[%s] WIN ht_curcap = %d ; vht_curcap = %d\n", __func__,
1990 ht_curbeamformcap, vht_curbeamformcap);
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));
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));
1999 #if (ODM_IC_11AC_SERIES_SUPPORT == 1)
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));
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));
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));
2013 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
2015 for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++) {
2016 sta = dm->phydm_sta_info[macid];
2018 if (!is_sta_active(sta))
2021 bf_info = &sta->bf_info;
2022 vht_curbeamformcap = bf_info->vht_beamform_cap;
2023 ht_curbeamformcap = bf_info->ht_beamform_cap;
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));
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));
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));
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));
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));
2046 PHYDM_DBG(dm, DBG_ANT_DIV, "[%s] CE ht_curcap = %d ; vht_curcap = %d\n",
2047 __func__, ht_curbeamformcap, vht_curbeamformcap);
2051 return beamform_cap;