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