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