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
19static 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******************************************/
46s32 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
102exit:
103
104 mutex_unlock(lock: &(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex));
105 return ret;
106}
107
108static 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
196static 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
223static 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. */
296void CheckFwRsvdPageContent(struct adapter *Adapter)
297{
298}
299
300static 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
313static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc)
314{
315}
316
317void 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
330void 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
346void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
347{
348 u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN] = {0};
349 u8 mac_id = *param;
350 u8 rssi = *(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
360void 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
457void 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
474void 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. */
494static 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
626error:
627
628 rtw_free_xmitframe(pxmitpriv, pxmitframe: pcmdframe);
629}
630
631void 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
719void 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 */
729void rtl8723b_Add_RateATid(
730 struct adapter *padapter,
731 u32 bitmap,
732 u8 *arg,
733 u8 rssi_level
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
758static 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
813static 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
893error:
894 rtw_free_xmitframe(pxmitpriv, pxmitframe: pcmdframe);
895}
896
897void 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

source code of linux/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c