xref: /linux/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c (revision 1641684528815bb7e85737d5d2bceb551c55d5a8)
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 
8 #include <drv_types.h>
9 #include <rtl8723b_hal.h>
10 #include "hal_com_h2c.h"
11 
12 #define MAX_H2C_BOX_NUMS	4
13 #define MESSAGE_BOX_SIZE	4
14 
15 #define RTL8723B_MAX_CMD_LEN	7
16 #define RTL8723B_EX_MESSAGE_BOX_SIZE	4
17 
_is_fw_read_cmd_down(struct adapter * padapter,u8 msgbox_num)18 static u8 _is_fw_read_cmd_down(struct adapter *padapter, u8 msgbox_num)
19 {
20 	u8 read_down = false;
21 	int retry_cnts = 100;
22 
23 	u8 valid;
24 
25 	do {
26 		valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num);
27 		if (0 == valid) {
28 			read_down = true;
29 		}
30 	} while ((!read_down) && (retry_cnts--));
31 
32 	return read_down;
33 
34 }
35 
36 
37 /*****************************************
38 * H2C Msg format :
39 *| 31 - 8		|7-5	| 4 - 0	|
40 *| h2c_msg	|Class	|CMD_ID	|
41 *| 31-0						|
42 *| Ext msg					|
43 *
44 ******************************************/
FillH2CCmd8723B(struct adapter * padapter,u8 ElementID,u32 CmdLen,u8 * pCmdBuffer)45 s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
46 {
47 	u8 h2c_box_num;
48 	u32 msgbox_addr;
49 	u32 msgbox_ex_addr = 0;
50 	struct hal_com_data *pHalData;
51 	u32 h2c_cmd = 0;
52 	u32 h2c_cmd_ex = 0;
53 	s32 ret = _FAIL;
54 
55 	padapter = GET_PRIMARY_ADAPTER(padapter);
56 	pHalData = GET_HAL_DATA(padapter);
57 	if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex)))
58 		return ret;
59 
60 	if (!pCmdBuffer)
61 		goto exit;
62 
63 	if (CmdLen > RTL8723B_MAX_CMD_LEN)
64 		goto exit;
65 
66 	if (padapter->bSurpriseRemoved)
67 		goto exit;
68 
69 	/* pay attention to if  race condition happened in  H2C cmd setting. */
70 	do {
71 		h2c_box_num = pHalData->LastHMEBoxNum;
72 
73 		if (!_is_fw_read_cmd_down(padapter, h2c_box_num))
74 			goto exit;
75 
76 		if (CmdLen <= 3)
77 			memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
78 		else {
79 			memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3);
80 			memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, CmdLen-3);
81 /* 			*(u8 *)(&h2c_cmd) |= BIT(7); */
82 		}
83 
84 		*(u8 *)(&h2c_cmd) |= ElementID;
85 
86 		if (CmdLen > 3) {
87 			msgbox_ex_addr = REG_HMEBOX_EXT0_8723B + (h2c_box_num*RTL8723B_EX_MESSAGE_BOX_SIZE);
88 			rtw_write32(padapter, msgbox_ex_addr, h2c_cmd_ex);
89 		}
90 		msgbox_addr = REG_HMEBOX_0 + (h2c_box_num*MESSAGE_BOX_SIZE);
91 		rtw_write32(padapter, msgbox_addr, h2c_cmd);
92 
93 		pHalData->LastHMEBoxNum = (h2c_box_num+1) % MAX_H2C_BOX_NUMS;
94 
95 	} while (0);
96 
97 	ret = _SUCCESS;
98 
99 exit:
100 
101 	mutex_unlock(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex));
102 	return ret;
103 }
104 
ConstructBeacon(struct adapter * padapter,u8 * pframe,u32 * pLength)105 static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength)
106 {
107 	struct ieee80211_hdr *pwlanhdr;
108 	__le16 *fctrl;
109 	u32 rate_len, pktlen;
110 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
111 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
112 	struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
113 
114 	pwlanhdr = (struct ieee80211_hdr *)pframe;
115 
116 	fctrl = &(pwlanhdr->frame_control);
117 	*(fctrl) = 0;
118 
119 	eth_broadcast_addr(pwlanhdr->addr1);
120 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
121 	memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
122 
123 	SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
124 	/* pmlmeext->mgnt_seq++; */
125 	SetFrameSubType(pframe, WIFI_BEACON);
126 
127 	pframe += sizeof(struct ieee80211_hdr_3addr);
128 	pktlen = sizeof(struct ieee80211_hdr_3addr);
129 
130 	/* timestamp will be inserted by hardware */
131 	pframe += 8;
132 	pktlen += 8;
133 
134 	/*  beacon interval: 2 bytes */
135 	memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->ies)), 2);
136 
137 	pframe += 2;
138 	pktlen += 2;
139 
140 	/*  capability info: 2 bytes */
141 	memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->ies)), 2);
142 
143 	pframe += 2;
144 	pktlen += 2;
145 
146 	if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
147 		pktlen += cur_network->ie_length - sizeof(struct ndis_802_11_fix_ie);
148 		memcpy(pframe, cur_network->ies+sizeof(struct ndis_802_11_fix_ie), pktlen);
149 
150 		goto _ConstructBeacon;
151 	}
152 
153 	/* below for ad-hoc mode */
154 
155 	/*  SSID */
156 	pframe = rtw_set_ie(pframe, WLAN_EID_SSID, cur_network->ssid.ssid_length, cur_network->ssid.ssid, &pktlen);
157 
158 	/*  supported rates... */
159 	rate_len = rtw_get_rateset_len(cur_network->supported_rates);
160 	pframe = rtw_set_ie(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ? 8 : rate_len), cur_network->supported_rates, &pktlen);
161 
162 	/*  DS parameter set */
163 	pframe = rtw_set_ie(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)&(cur_network->configuration.ds_config), &pktlen);
164 
165 	if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
166 		u32 ATIMWindow;
167 		/*  IBSS Parameter Set... */
168 		/* ATIMWindow = cur->configuration.ATIMWindow; */
169 		ATIMWindow = 0;
170 		pframe = rtw_set_ie(pframe, WLAN_EID_IBSS_PARAMS, 2, (unsigned char *)(&ATIMWindow), &pktlen);
171 	}
172 
173 
174 	/* todo: ERP IE */
175 
176 
177 	/*  EXTERNDED SUPPORTED RATE */
178 	if (rate_len > 8)
179 		pframe = rtw_set_ie(pframe, WLAN_EID_EXT_SUPP_RATES, (rate_len - 8), (cur_network->supported_rates + 8), &pktlen);
180 
181 
182 	/* todo:HT for adhoc */
183 
184 _ConstructBeacon:
185 
186 	if ((pktlen + TXDESC_SIZE) > 512)
187 		return;
188 
189 	*pLength = pktlen;
190 
191 }
192 
ConstructPSPoll(struct adapter * padapter,u8 * pframe,u32 * pLength)193 static void ConstructPSPoll(struct adapter *padapter, u8 *pframe, u32 *pLength)
194 {
195 	struct ieee80211_hdr *pwlanhdr;
196 	__le16 *fctrl;
197 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
198 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
199 
200 	pwlanhdr = (struct ieee80211_hdr *)pframe;
201 
202 	/*  Frame control. */
203 	fctrl = &(pwlanhdr->frame_control);
204 	*(fctrl) = 0;
205 	SetPwrMgt(fctrl);
206 	SetFrameSubType(pframe, WIFI_PSPOLL);
207 
208 	/*  AID. */
209 	SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
210 
211 	/*  BSSID. */
212 	memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
213 
214 	/*  TA. */
215 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
216 
217 	*pLength = 16;
218 }
219 
ConstructNullFunctionData(struct adapter * padapter,u8 * pframe,u32 * pLength,u8 * StaAddr,u8 bQoS,u8 AC,u8 bEosp,u8 bForcePowerSave)220 static void ConstructNullFunctionData(
221 	struct adapter *padapter,
222 	u8 *pframe,
223 	u32 *pLength,
224 	u8 *StaAddr,
225 	u8 bQoS,
226 	u8 AC,
227 	u8 bEosp,
228 	u8 bForcePowerSave
229 )
230 {
231 	struct ieee80211_hdr *pwlanhdr;
232 	__le16 *fctrl;
233 	u32 pktlen;
234 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
235 	struct wlan_network *cur_network = &pmlmepriv->cur_network;
236 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
237 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
238 
239 	pwlanhdr = (struct ieee80211_hdr *)pframe;
240 
241 	fctrl = &pwlanhdr->frame_control;
242 	*(fctrl) = 0;
243 	if (bForcePowerSave)
244 		SetPwrMgt(fctrl);
245 
246 	switch (cur_network->network.infrastructure_mode) {
247 	case Ndis802_11Infrastructure:
248 		SetToDs(fctrl);
249 		memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
250 		memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
251 		memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
252 		break;
253 	case Ndis802_11APMode:
254 		SetFrDs(fctrl);
255 		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
256 		memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
257 		memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
258 		break;
259 	case Ndis802_11IBSS:
260 	default:
261 		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
262 		memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
263 		memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
264 		break;
265 	}
266 
267 	SetSeqNum(pwlanhdr, 0);
268 
269 	if (bQoS) {
270 		struct ieee80211_qos_hdr *pwlanqoshdr;
271 
272 		SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
273 
274 		pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe;
275 		SetPriority(&pwlanqoshdr->qos_ctrl, AC);
276 		SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp);
277 
278 		pktlen = sizeof(struct ieee80211_qos_hdr);
279 	} else {
280 		SetFrameSubType(pframe, WIFI_DATA_NULL);
281 
282 		pktlen = sizeof(struct ieee80211_hdr_3addr);
283 	}
284 
285 	*pLength = pktlen;
286 }
287 
rtl8723b_set_FwRsvdPage_cmd(struct adapter * padapter,struct rsvdpage_loc * rsvdpageloc)288 static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc)
289 {
290 	u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0};
291 
292 	SET_8723B_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp);
293 	SET_8723B_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll);
294 	SET_8723B_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData);
295 	SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull);
296 	SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull);
297 
298 	FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm);
299 }
300 
rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter * padapter,u8 mstatus,u8 macid)301 void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid)
302 {
303 	u8 u1H2CMediaStatusRptParm[H2C_MEDIA_STATUS_RPT_LEN] = {0};
304 	u8 macid_end = 0;
305 
306 	SET_8723B_H2CCMD_MSRRPT_PARM_OPMODE(u1H2CMediaStatusRptParm, mstatus);
307 	SET_8723B_H2CCMD_MSRRPT_PARM_MACID_IND(u1H2CMediaStatusRptParm, 0);
308 	SET_8723B_H2CCMD_MSRRPT_PARM_MACID(u1H2CMediaStatusRptParm, macid);
309 	SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(u1H2CMediaStatusRptParm, macid_end);
310 
311 	FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm);
312 }
313 
rtl8723b_set_FwMacIdConfig_cmd(struct adapter * padapter,u8 mac_id,u8 raid,u8 bw,u8 sgi,u32 mask)314 void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid, u8 bw, u8 sgi, u32 mask)
315 {
316 	u8 u1H2CMacIdConfigParm[H2C_MACID_CFG_LEN] = {0};
317 
318 	SET_8723B_H2CCMD_MACID_CFG_MACID(u1H2CMacIdConfigParm, mac_id);
319 	SET_8723B_H2CCMD_MACID_CFG_RAID(u1H2CMacIdConfigParm, raid);
320 	SET_8723B_H2CCMD_MACID_CFG_SGI_EN(u1H2CMacIdConfigParm, sgi ? 1 : 0);
321 	SET_8723B_H2CCMD_MACID_CFG_BW(u1H2CMacIdConfigParm, bw);
322 	SET_8723B_H2CCMD_MACID_CFG_RATE_MASK0(u1H2CMacIdConfigParm, (u8)(mask & 0x000000ff));
323 	SET_8723B_H2CCMD_MACID_CFG_RATE_MASK1(u1H2CMacIdConfigParm, (u8)((mask & 0x0000ff00) >> 8));
324 	SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(u1H2CMacIdConfigParm, (u8)((mask & 0x00ff0000) >> 16));
325 	SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(u1H2CMacIdConfigParm, (u8)((mask & 0xff000000) >> 24));
326 
327 	FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm);
328 }
329 
rtl8723b_set_rssi_cmd(struct adapter * padapter,u8 * param)330 void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
331 {
332 	u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN] = {0};
333 	u8 mac_id = *param;
334 	u8 rssi = *(param+2);
335 	u8 uldl_state = 0;
336 
337 	SET_8723B_H2CCMD_RSSI_SETTING_MACID(u1H2CRssiSettingParm, mac_id);
338 	SET_8723B_H2CCMD_RSSI_SETTING_RSSI(u1H2CRssiSettingParm, rssi);
339 	SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(u1H2CRssiSettingParm, uldl_state);
340 
341 	FillH2CCmd8723B(padapter, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, u1H2CRssiSettingParm);
342 }
343 
rtl8723b_set_FwPwrMode_cmd(struct adapter * padapter,u8 psmode)344 void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
345 {
346 	int i;
347 	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
348 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
349 	u8 u1H2CPwrModeParm[H2C_PWRMODE_LEN] = {0};
350 	u8 PowerState = 0, awake_intvl = 1, byte5 = 0, rlbm = 0;
351 
352 	if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16)
353 		awake_intvl = pwrpriv->dtim+1;/* DTIM = (awake_intvl - 1) */
354 	else
355 		awake_intvl = 3;/* DTIM =2 */
356 
357 	rlbm = 2;
358 
359 	if (padapter->registrypriv.wifi_spec == 1) {
360 		awake_intvl = 2;
361 		rlbm = 2;
362 	}
363 
364 	if (psmode > 0) {
365 		if (hal_btcoex_IsBtControlLps(padapter) == true) {
366 			PowerState = hal_btcoex_RpwmVal(padapter);
367 			byte5 = hal_btcoex_LpsVal(padapter);
368 
369 			if ((rlbm == 2) && (byte5 & BIT(4))) {
370 				/*  Keep awake interval to 1 to prevent from */
371 				/*  decreasing coex performance */
372 				awake_intvl = 2;
373 				rlbm = 2;
374 			}
375 		} else {
376 			PowerState = 0x00;/*  AllON(0x0C), RFON(0x04), RFOFF(0x00) */
377 			byte5 = 0x40;
378 		}
379 	} else {
380 		PowerState = 0x0C;/*  AllON(0x0C), RFON(0x04), RFOFF(0x00) */
381 		byte5 = 0x40;
382 	}
383 
384 	SET_8723B_H2CCMD_PWRMODE_PARM_MODE(u1H2CPwrModeParm, (psmode > 0) ? 1 : 0);
385 	SET_8723B_H2CCMD_PWRMODE_PARM_SMART_PS(u1H2CPwrModeParm, pwrpriv->smart_ps);
386 	SET_8723B_H2CCMD_PWRMODE_PARM_RLBM(u1H2CPwrModeParm, rlbm);
387 	SET_8723B_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1H2CPwrModeParm, awake_intvl);
388 	SET_8723B_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1H2CPwrModeParm, padapter->registrypriv.uapsd_enable);
389 	SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(u1H2CPwrModeParm, PowerState);
390 	SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(u1H2CPwrModeParm, byte5);
391 	if (psmode != PS_MODE_ACTIVE) {
392 		if (!pmlmeext->adaptive_tsf_done && pmlmeext->bcn_cnt > 0) {
393 			u8 ratio_20_delay, ratio_80_delay;
394 
395 			/* byte 6 for adaptive_early_32k */
396 			/* 0:3] = DrvBcnEarly  (ms) , [4:7] = DrvBcnTimeOut  (ms) */
397 			/*  20% for DrvBcnEarly, 80% for DrvBcnTimeOut */
398 			ratio_20_delay = 0;
399 			ratio_80_delay = 0;
400 			pmlmeext->DrvBcnEarly = 0xff;
401 			pmlmeext->DrvBcnTimeOut = 0xff;
402 
403 			for (i = 0; i < 9; i++) {
404 				pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i]*100)/pmlmeext->bcn_cnt;
405 
406 				ratio_20_delay += pmlmeext->bcn_delay_ratio[i];
407 				ratio_80_delay += pmlmeext->bcn_delay_ratio[i];
408 
409 				if (ratio_20_delay > 20 && pmlmeext->DrvBcnEarly == 0xff)
410 					pmlmeext->DrvBcnEarly = i;
411 
412 				if (ratio_80_delay > 80 && pmlmeext->DrvBcnTimeOut == 0xff)
413 					pmlmeext->DrvBcnTimeOut = i;
414 
415 				/* reset adaptive_early_32k cnt */
416 				pmlmeext->bcn_delay_cnt[i] = 0;
417 				pmlmeext->bcn_delay_ratio[i] = 0;
418 
419 			}
420 
421 			pmlmeext->bcn_cnt = 0;
422 			pmlmeext->adaptive_tsf_done = true;
423 
424 		}
425 
426 /* offload to FW if fw version > v15.10
427 		pmlmeext->DrvBcnEarly = 0;
428 		pmlmeext->DrvBcnTimeOut =7;
429 
430 		if ((pmlmeext->DrvBcnEarly!= 0Xff) && (pmlmeext->DrvBcnTimeOut!= 0xff))
431 			u1H2CPwrModeParm[H2C_PWRMODE_LEN-1] = BIT(0) | ((pmlmeext->DrvBcnEarly<<1)&0x0E) |((pmlmeext->DrvBcnTimeOut<<4)&0xf0) ;
432 */
433 
434 	}
435 
436 	hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
437 
438 	FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, u1H2CPwrModeParm);
439 }
440 
rtl8723b_set_FwPsTuneParam_cmd(struct adapter * padapter)441 void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter)
442 {
443 	u8 u1H2CPsTuneParm[H2C_PSTUNEPARAM_LEN] = {0};
444 	u8 bcn_to_limit = 10; /* 10 * 100 * awakeinterval (ms) */
445 	u8 dtim_timeout = 5; /* ms wait broadcast data timer */
446 	u8 ps_timeout = 20;  /* ms Keep awake when tx */
447 	u8 dtim_period = 3;
448 
449 	SET_8723B_H2CCMD_PSTUNE_PARM_BCN_TO_LIMIT(u1H2CPsTuneParm, bcn_to_limit);
450 	SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_TIMEOUT(u1H2CPsTuneParm, dtim_timeout);
451 	SET_8723B_H2CCMD_PSTUNE_PARM_PS_TIMEOUT(u1H2CPsTuneParm, ps_timeout);
452 	SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(u1H2CPsTuneParm, 1);
453 	SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(u1H2CPsTuneParm, dtim_period);
454 
455 	FillH2CCmd8723B(padapter, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm);
456 }
457 
rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter * padapter,u8 cmd_param)458 void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param)
459 {
460 
461 	FillH2CCmd8723B(padapter, H2C_8723B_FWLPS_IN_IPS_, 1, &cmd_param);
462 }
463 
464 /*
465  * Description: Fill the reserved packets that FW will use to RSVD page.
466  * Now we just send 4 types packet to rsvd page.
467  * (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp.
468  *
469  * Input:
470  *
471  * bDLFinished - false: At the first time we will send all the packets as
472  * a large packet to Hw, so we need to set the packet length to total length.
473  *
474  * true: At the second time, we should send the first packet (default:beacon)
475  * to Hw again and set the length in descriptor to the real beacon length.
476  */
477 /* 2009.10.15 by tynli. */
rtl8723b_set_FwRsvdPagePkt(struct adapter * padapter,bool bDLFinished)478 static void rtl8723b_set_FwRsvdPagePkt(
479 	struct adapter *padapter, bool bDLFinished
480 )
481 {
482 	struct xmit_frame *pcmdframe;
483 	struct pkt_attrib *pattrib;
484 	struct xmit_priv *pxmitpriv;
485 	struct mlme_ext_priv *pmlmeext;
486 	struct mlme_ext_info *pmlmeinfo;
487 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
488 	u32 BeaconLength = 0, PSPollLength = 0;
489 	u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0;
490 	u8 *ReservedPagePacket;
491 	u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET;
492 	u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0;
493 	u16 BufIndex, PageSize = 128;
494 	u32 TotalPacketLen, MaxRsvdPageBufSize = 0;
495 
496 	struct rsvdpage_loc RsvdPageLoc;
497 
498 	pxmitpriv = &padapter->xmitpriv;
499 	pmlmeext = &padapter->mlmeextpriv;
500 	pmlmeinfo = &pmlmeext->mlmext_info;
501 
502 	RsvdPageNum = BCNQ_PAGE_NUM_8723B + WOWLAN_PAGE_NUM_8723B;
503 	MaxRsvdPageBufSize = RsvdPageNum*PageSize;
504 
505 	pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
506 	if (!pcmdframe)
507 		return;
508 
509 	ReservedPagePacket = pcmdframe->buf_addr;
510 	memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc));
511 
512 	/* 3 (1) beacon */
513 	BufIndex = TxDescOffset;
514 	ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
515 
516 	/*  When we count the first page size, we need to reserve description size for the RSVD */
517 	/*  packet, it will be filled in front of the packet in TXPKTBUF. */
518 	CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength);
519 	/* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */
520 	if (CurtPktPageNum == 1)
521 		CurtPktPageNum += 1;
522 
523 	TotalPageNum += CurtPktPageNum;
524 
525 	BufIndex += (CurtPktPageNum*PageSize);
526 
527 	/* 3 (2) ps-poll */
528 	RsvdPageLoc.LocPsPoll = TotalPageNum;
529 	ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength);
530 	rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false, false);
531 
532 	CurtPktPageNum = (u8)PageNum_128(TxDescLen + PSPollLength);
533 
534 	TotalPageNum += CurtPktPageNum;
535 
536 	BufIndex += (CurtPktPageNum*PageSize);
537 
538 	/* 3 (3) null data */
539 	RsvdPageLoc.LocNullData = TotalPageNum;
540 	ConstructNullFunctionData(
541 		padapter,
542 		&ReservedPagePacket[BufIndex],
543 		&NullDataLength,
544 		get_my_bssid(&pmlmeinfo->network),
545 		false, 0, 0, false
546 	);
547 	rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false, false);
548 
549 	CurtPktPageNum = (u8)PageNum_128(TxDescLen + NullDataLength);
550 
551 	TotalPageNum += CurtPktPageNum;
552 
553 	BufIndex += (CurtPktPageNum*PageSize);
554 
555 	/* 3 (5) Qos null data */
556 	RsvdPageLoc.LocQosNull = TotalPageNum;
557 	ConstructNullFunctionData(
558 		padapter,
559 		&ReservedPagePacket[BufIndex],
560 		&QosNullLength,
561 		get_my_bssid(&pmlmeinfo->network),
562 		true, 0, 0, false
563 	);
564 	rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false, false);
565 
566 	CurtPktPageNum = (u8)PageNum_128(TxDescLen + QosNullLength);
567 
568 	TotalPageNum += CurtPktPageNum;
569 
570 	BufIndex += (CurtPktPageNum*PageSize);
571 
572 	/* 3 (6) BT Qos null data */
573 	RsvdPageLoc.LocBTQosNull = TotalPageNum;
574 	ConstructNullFunctionData(
575 		padapter,
576 		&ReservedPagePacket[BufIndex],
577 		&BTQosNullLength,
578 		get_my_bssid(&pmlmeinfo->network),
579 		true, 0, 0, false
580 	);
581 	rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false);
582 
583 	CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength);
584 
585 	TotalPageNum += CurtPktPageNum;
586 
587 	BufIndex += (CurtPktPageNum*PageSize);
588 
589 	TotalPacketLen = BufIndex + BTQosNullLength;
590 
591 	if (TotalPacketLen > MaxRsvdPageBufSize) {
592 		goto error;
593 	} else {
594 		/*  update attribute */
595 		pattrib = &pcmdframe->attrib;
596 		update_mgntframe_attrib(padapter, pattrib);
597 		pattrib->qsel = 0x10;
598 		pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset;
599 		dump_mgntframe_and_wait(padapter, pcmdframe, 100);
600 	}
601 
602 	if (check_fwstate(pmlmepriv, _FW_LINKED))
603 		rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc);
604 
605 	return;
606 
607 error:
608 
609 	rtw_free_xmitframe(pxmitpriv, pcmdframe);
610 }
611 
rtl8723b_download_rsvd_page(struct adapter * padapter,u8 mstatus)612 void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus)
613 {
614 	struct hal_com_data	*pHalData = GET_HAL_DATA(padapter);
615 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
616 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
617 	bool bcn_valid = false;
618 	u8 DLBcnCount = 0;
619 	u32 poll = 0;
620 	u8 val8;
621 
622 	if (mstatus == RT_MEDIA_CONNECT) {
623 		bool bRecover = false;
624 		u8 v8;
625 
626 		/*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
627 		/*  Suggested by filen. Added by tynli. */
628 		rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
629 
630 		/*  set REG_CR bit 8 */
631 		v8 = rtw_read8(padapter, REG_CR+1);
632 		v8 |= BIT(0); /*  ENSWBCN */
633 		rtw_write8(padapter, REG_CR+1, v8);
634 
635 		/*  Disable Hw protection for a time which revserd for Hw sending beacon. */
636 		/*  Fix download reserved page packet fail that access collision with the protection time. */
637 		/*  2010.05.11. Added by tynli. */
638 		val8 = rtw_read8(padapter, REG_BCN_CTRL);
639 		val8 &= ~EN_BCN_FUNCTION;
640 		val8 |= DIS_TSF_UDT;
641 		rtw_write8(padapter, REG_BCN_CTRL, val8);
642 
643 		/*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
644 		if (pHalData->RegFwHwTxQCtrl & BIT(6))
645 			bRecover = true;
646 
647 		/*  To tell Hw the packet is not a real beacon frame. */
648 		rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6));
649 		pHalData->RegFwHwTxQCtrl &= ~BIT(6);
650 
651 		/*  Clear beacon valid check bit. */
652 		rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
653 		rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
654 
655 		DLBcnCount = 0;
656 		poll = 0;
657 		do {
658 			/*  download rsvd page. */
659 			rtl8723b_set_FwRsvdPagePkt(padapter, 0);
660 			DLBcnCount++;
661 			do {
662 				yield();
663 				/* mdelay(10); */
664 				/*  check rsvd page download OK. */
665 				rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid));
666 				poll++;
667 			} while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
668 
669 		} while (!bcn_valid && DLBcnCount <= 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
670 
671 		if (padapter->bSurpriseRemoved || padapter->bDriverStopped) {
672 		} else {
673 			struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
674 			pwrctl->fw_psmode_iface_id = padapter->iface_id;
675 		}
676 
677 		/*  2010.05.11. Added by tynli. */
678 		val8 = rtw_read8(padapter, REG_BCN_CTRL);
679 		val8 |= EN_BCN_FUNCTION;
680 		val8 &= ~DIS_TSF_UDT;
681 		rtw_write8(padapter, REG_BCN_CTRL, val8);
682 
683 		/*  To make sure that if there exists an adapter which would like to send beacon. */
684 		/*  If exists, the original value of 0x422[6] will be 1, we should check this to */
685 		/*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
686 		/*  the beacon cannot be sent by HW. */
687 		/*  2010.06.23. Added by tynli. */
688 		if (bRecover) {
689 			rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6));
690 			pHalData->RegFwHwTxQCtrl |= BIT(6);
691 		}
692 
693 		/*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
694 		v8 = rtw_read8(padapter, REG_CR+1);
695 		v8 &= ~BIT(0); /*  ~ENSWBCN */
696 		rtw_write8(padapter, REG_CR+1, v8);
697 	}
698 }
699 
rtl8723b_set_FwJoinBssRpt_cmd(struct adapter * padapter,u8 mstatus)700 void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus)
701 {
702 	if (mstatus == 1)
703 		rtl8723b_download_rsvd_page(padapter, RT_MEDIA_CONNECT);
704 }
705 
706 /* arg[0] = macid */
707 /* arg[1] = raid */
708 /* arg[2] = shortGIrate */
709 /* arg[3] = init_rate */
rtl8723b_Add_RateATid(struct adapter * padapter,u32 bitmap,u8 * arg,u8 rssi_level)710 void rtl8723b_Add_RateATid(
711 	struct adapter *padapter,
712 	u32 bitmap,
713 	u8 *arg,
714 	u8 rssi_level
715 )
716 {
717 	struct hal_com_data	*pHalData = GET_HAL_DATA(padapter);
718 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
719 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
720 	struct sta_info *psta;
721 	u8 mac_id = arg[0];
722 	u8 raid = arg[1];
723 	u8 shortGI = arg[2];
724 	u8 bw;
725 	u32 mask = bitmap&0x0FFFFFFF;
726 
727 	psta = pmlmeinfo->FW_sta_info[mac_id].psta;
728 	if (!psta)
729 		return;
730 
731 	bw = psta->bw_mode;
732 
733 	if (rssi_level != DM_RATR_STA_INIT)
734 		mask = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level);
735 
736 	rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid, bw, shortGI, mask);
737 }
738 
ConstructBtNullFunctionData(struct adapter * padapter,u8 * pframe,u32 * pLength,u8 * StaAddr,u8 bQoS,u8 AC,u8 bEosp,u8 bForcePowerSave)739 static void ConstructBtNullFunctionData(
740 	struct adapter *padapter,
741 	u8 *pframe,
742 	u32 *pLength,
743 	u8 *StaAddr,
744 	u8 bQoS,
745 	u8 AC,
746 	u8 bEosp,
747 	u8 bForcePowerSave
748 )
749 {
750 	struct ieee80211_hdr *pwlanhdr;
751 	__le16 *fctrl;
752 	u32 pktlen;
753 	u8 bssid[ETH_ALEN];
754 
755 	pwlanhdr = (struct ieee80211_hdr *)pframe;
756 
757 	if (!StaAddr) {
758 		memcpy(bssid, myid(&padapter->eeprompriv), ETH_ALEN);
759 		StaAddr = bssid;
760 	}
761 
762 	fctrl = &pwlanhdr->frame_control;
763 	*fctrl = 0;
764 	if (bForcePowerSave)
765 		SetPwrMgt(fctrl);
766 
767 	SetFrDs(fctrl);
768 	memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
769 	memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
770 	memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN);
771 
772 	SetDuration(pwlanhdr, 0);
773 	SetSeqNum(pwlanhdr, 0);
774 
775 	if (bQoS) {
776 		struct ieee80211_qos_hdr *pwlanqoshdr;
777 
778 		SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
779 
780 		pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe;
781 		SetPriority(&pwlanqoshdr->qos_ctrl, AC);
782 		SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp);
783 
784 		pktlen = sizeof(struct ieee80211_qos_hdr);
785 	} else {
786 		SetFrameSubType(pframe, WIFI_DATA_NULL);
787 
788 		pktlen = sizeof(struct ieee80211_hdr_3addr);
789 	}
790 
791 	*pLength = pktlen;
792 }
793 
SetFwRsvdPagePkt_BTCoex(struct adapter * padapter)794 static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter)
795 {
796 	struct xmit_frame *pcmdframe;
797 	struct pkt_attrib *pattrib;
798 	struct xmit_priv *pxmitpriv;
799 	u32 BeaconLength = 0;
800 	u32 BTQosNullLength = 0;
801 	u8 *ReservedPagePacket;
802 	u8 TxDescLen, TxDescOffset;
803 	u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0;
804 	u16 BufIndex, PageSize;
805 	u32 TotalPacketLen, MaxRsvdPageBufSize = 0;
806 	struct rsvdpage_loc RsvdPageLoc;
807 
808 	pxmitpriv = &padapter->xmitpriv;
809 	TxDescLen = TXDESC_SIZE;
810 	TxDescOffset = TXDESC_OFFSET;
811 	PageSize = PAGE_SIZE_TX_8723B;
812 
813 	RsvdPageNum = BCNQ_PAGE_NUM_8723B;
814 	MaxRsvdPageBufSize = RsvdPageNum*PageSize;
815 
816 	pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
817 	if (!pcmdframe)
818 		return;
819 
820 	ReservedPagePacket = pcmdframe->buf_addr;
821 	memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc));
822 
823 	/* 3 (1) beacon */
824 	BufIndex = TxDescOffset;
825 	ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
826 
827 	/*  When we count the first page size, we need to reserve description size for the RSVD */
828 	/*  packet, it will be filled in front of the packet in TXPKTBUF. */
829 	CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength);
830 	/* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */
831 	if (CurtPktPageNum == 1)
832 		CurtPktPageNum += 1;
833 	TotalPageNum += CurtPktPageNum;
834 
835 	BufIndex += (CurtPktPageNum*PageSize);
836 
837 	/*  Jump to lastest page */
838 	if (BufIndex < (MaxRsvdPageBufSize - PageSize)) {
839 		BufIndex = TxDescOffset + (MaxRsvdPageBufSize - PageSize);
840 		TotalPageNum = BCNQ_PAGE_NUM_8723B - 1;
841 	}
842 
843 	/* 3 (6) BT Qos null data */
844 	RsvdPageLoc.LocBTQosNull = TotalPageNum;
845 	ConstructBtNullFunctionData(
846 		padapter,
847 		&ReservedPagePacket[BufIndex],
848 		&BTQosNullLength,
849 		NULL,
850 		true, 0, 0, false
851 	);
852 	rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false);
853 
854 	CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength);
855 
856 	TotalPageNum += CurtPktPageNum;
857 
858 	TotalPacketLen = BufIndex + BTQosNullLength;
859 	if (TotalPacketLen > MaxRsvdPageBufSize)
860 		goto error;
861 
862 	/*  update attribute */
863 	pattrib = &pcmdframe->attrib;
864 	update_mgntframe_attrib(padapter, pattrib);
865 	pattrib->qsel = 0x10;
866 	pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset;
867 	dump_mgntframe_and_wait(padapter, pcmdframe, 100);
868 
869 	rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc);
870 
871 	return;
872 
873 error:
874 	rtw_free_xmitframe(pxmitpriv, pcmdframe);
875 }
876 
rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter * padapter)877 void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter)
878 {
879 	struct hal_com_data *pHalData;
880 	struct mlme_ext_priv *pmlmeext;
881 	struct mlme_ext_info *pmlmeinfo;
882 	u8 bRecover = false;
883 	u8 bcn_valid = false;
884 	u8 DLBcnCount = 0;
885 	u32 poll = 0;
886 	u8 val8;
887 
888 	pHalData = GET_HAL_DATA(padapter);
889 	pmlmeext = &padapter->mlmeextpriv;
890 	pmlmeinfo = &pmlmeext->mlmext_info;
891 
892 	/*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
893 	/*  Suggested by filen. Added by tynli. */
894 	rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
895 
896 	/*  set REG_CR bit 8 */
897 	val8 = rtw_read8(padapter, REG_CR+1);
898 	val8 |= BIT(0); /*  ENSWBCN */
899 	rtw_write8(padapter,  REG_CR+1, val8);
900 
901 	/*  Disable Hw protection for a time which revserd for Hw sending beacon. */
902 	/*  Fix download reserved page packet fail that access collision with the protection time. */
903 	/*  2010.05.11. Added by tynli. */
904 	val8 = rtw_read8(padapter, REG_BCN_CTRL);
905 	val8 &= ~EN_BCN_FUNCTION;
906 	val8 |= DIS_TSF_UDT;
907 	rtw_write8(padapter, REG_BCN_CTRL, val8);
908 
909 	/*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
910 	if (pHalData->RegFwHwTxQCtrl & BIT(6))
911 		bRecover = true;
912 
913 	/*  To tell Hw the packet is not a real beacon frame. */
914 	pHalData->RegFwHwTxQCtrl &= ~BIT(6);
915 	rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
916 
917 	/*  Clear beacon valid check bit. */
918 	rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
919 	rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
920 
921 	DLBcnCount = 0;
922 	poll = 0;
923 	do {
924 		SetFwRsvdPagePkt_BTCoex(padapter);
925 		DLBcnCount++;
926 		do {
927 			yield();
928 /* 			mdelay(10); */
929 			/*  check rsvd page download OK. */
930 			rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, &bcn_valid);
931 			poll++;
932 		} while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
933 	} while (!bcn_valid && (DLBcnCount <= 100) && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
934 
935 	if (bcn_valid) {
936 		struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
937 		pwrctl->fw_psmode_iface_id = padapter->iface_id;
938 	}
939 
940 	/*  2010.05.11. Added by tynli. */
941 	val8 = rtw_read8(padapter, REG_BCN_CTRL);
942 	val8 |= EN_BCN_FUNCTION;
943 	val8 &= ~DIS_TSF_UDT;
944 	rtw_write8(padapter, REG_BCN_CTRL, val8);
945 
946 	/*  To make sure that if there exists an adapter which would like to send beacon. */
947 	/*  If exists, the original value of 0x422[6] will be 1, we should check this to */
948 	/*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
949 	/*  the beacon cannot be sent by HW. */
950 	/*  2010.06.23. Added by tynli. */
951 	if (bRecover) {
952 		pHalData->RegFwHwTxQCtrl |= BIT(6);
953 		rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
954 	}
955 
956 	/*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
957 	val8 = rtw_read8(padapter, REG_CR+1);
958 	val8 &= ~BIT(0); /*  ~ENSWBCN */
959 	rtw_write8(padapter, REG_CR+1, val8);
960 }
961