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