GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / staging / rtl8723bs / hal / rtl8723b_cmd.c
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(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, 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(padapter, msgbox_ex_addr, h2c_cmd_ex);
92                 }
93                 msgbox_addr = REG_HMEBOX_0 + (h2c_box_num*MESSAGE_BOX_SIZE);
94                 rtw_write32(padapter, msgbox_addr, 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(&(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(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(pframe, WLAN_EID_SSID, cur_network->ssid.ssid_length, cur_network->ssid.ssid, &pktlen);
160
161         /*  supported rates... */
162         rate_len = rtw_get_rateset_len(cur_network->supported_rates);
163         pframe = rtw_set_ie(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ? 8 : rate_len), cur_network->supported_rates, &pktlen);
164
165         /*  DS parameter set */
166         pframe = rtw_set_ie(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)&(cur_network->configuration.ds_config), &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(pframe, WLAN_EID_IBSS_PARAMS, 2, (unsigned char *)(&ATIMWindow), &pktlen);
174         }
175
176
177         /* todo: ERP IE */
178
179
180         /*  EXTERNDED SUPPORTED RATE */
181         if (rate_len > 8)
182                 pframe = rtw_set_ie(pframe, WLAN_EID_EXT_SUPP_RATES, (rate_len - 8), (cur_network->supported_rates + 8), &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, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, 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, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, 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, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm);
344 }
345
346 void 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, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, 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, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
453
454         FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, 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, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm);
472 }
473
474 void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param)
475 {
476
477         FillH2CCmd8723B(padapter, H2C_8723B_FWLPS_IN_IPS_, 1, &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, &ReservedPagePacket[BufIndex], &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, &ReservedPagePacket[BufIndex], &PSPollLength);
546         rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false, 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                 &ReservedPagePacket[BufIndex],
559                 &NullDataLength,
560                 get_my_bssid(&pmlmeinfo->network),
561                 false, 0, 0, false
562         );
563         rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false, 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                 &ReservedPagePacket[BufIndex],
576                 &QosNullLength,
577                 get_my_bssid(&pmlmeinfo->network),
578                 true, 0, 0, false
579         );
580         rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false, 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                 &ReservedPagePacket[BufIndex],
593                 &BTQosNullLength,
594                 get_my_bssid(&pmlmeinfo->network),
595                 true, 0, 0, false
596         );
597         rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, 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, pcmdframe, 100);
616         }
617
618         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
619                 rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc);
620                 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc);
621         } else {
622                 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc);
623         }
624         return;
625
626 error:
627
628         rtw_free_xmitframe(pxmitpriv, 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(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
648
649                 /*  set REG_CR bit 8 */
650                 v8 = rtw_read8(padapter, REG_CR+1);
651                 v8 |= BIT(0); /*  ENSWBCN */
652                 rtw_write8(padapter, REG_CR+1, 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(padapter, REG_BCN_CTRL);
658                 val8 &= ~EN_BCN_FUNCTION;
659                 val8 |= DIS_TSF_UDT;
660                 rtw_write8(padapter, REG_BCN_CTRL, 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(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6));
668                 pHalData->RegFwHwTxQCtrl &= ~BIT(6);
669
670                 /*  Clear beacon valid check bit. */
671                 rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
672                 rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
673
674                 DLBcnCount = 0;
675                 poll = 0;
676                 do {
677                         /*  download rsvd page. */
678                         rtl8723b_set_FwRsvdPagePkt(padapter, 0);
679                         DLBcnCount++;
680                         do {
681                                 yield();
682                                 /* mdelay(10); */
683                                 /*  check rsvd page download OK. */
684                                 rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (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(padapter, REG_BCN_CTRL);
698                 val8 |= EN_BCN_FUNCTION;
699                 val8 &= ~DIS_TSF_UDT;
700                 rtw_write8(padapter, REG_BCN_CTRL, 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(padapter, REG_FWHW_TXQ_CTRL+2, 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(padapter, REG_CR+1);
714                 v8 &= ~BIT(0); /*  ~ENSWBCN */
715                 rtw_write8(padapter, REG_CR+1, 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, 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 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(&pHalData->odmpriv, mac_id, mask, rssi_level);
754
755         rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid, bw, 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, &ReservedPagePacket[BufIndex], &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                 &ReservedPagePacket[BufIndex],
867                 &BTQosNullLength,
868                 NULL,
869                 true, 0, 0, false
870         );
871         rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, 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, pcmdframe, 100);
887
888         rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc);
889         rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc);
890
891         return;
892
893 error:
894         rtw_free_xmitframe(pxmitpriv, 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(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
915
916         /*  set REG_CR bit 8 */
917         val8 = rtw_read8(padapter, REG_CR+1);
918         val8 |= BIT(0); /*  ENSWBCN */
919         rtw_write8(padapter,  REG_CR+1, 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(padapter, REG_BCN_CTRL);
925         val8 &= ~EN_BCN_FUNCTION;
926         val8 |= DIS_TSF_UDT;
927         rtw_write8(padapter, REG_BCN_CTRL, 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(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
936
937         /*  Clear beacon valid check bit. */
938         rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
939         rtw_hal_set_hwreg(padapter, 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, HW_VAR_BCN_VALID, &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(padapter, REG_BCN_CTRL);
962         val8 |= EN_BCN_FUNCTION;
963         val8 &= ~DIS_TSF_UDT;
964         rtw_write8(padapter, REG_BCN_CTRL, 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(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
974         }
975
976         /*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
977         val8 = rtw_read8(padapter, REG_CR+1);
978         val8 &= ~BIT(0); /*  ~ENSWBCN */
979         rtw_write8(padapter, REG_CR+1, val8);
980 }