Linux 3.15-rc2
[firefly-linux-kernel-4.4.55.git] / drivers / staging / rtl8723au / hal / rtl8723a_cmd.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  ******************************************************************************/
15 #define _RTL8723A_CMD_C_
16
17 #include <osdep_service.h>
18 #include <drv_types.h>
19 #include <recv_osdep.h>
20 #include <cmd_osdep.h>
21 #include <mlme_osdep.h>
22 #include <rtw_ioctl_set.h>
23 #include <rtl8723a_hal.h>
24
25 #define RTL92C_MAX_H2C_BOX_NUMS         4
26 #define RTL92C_MAX_CMD_LEN              5
27 #define MESSAGE_BOX_SIZE                4
28 #define EX_MESSAGE_BOX_SIZE             2
29
30 static u8 _is_fw_read_cmd_down(struct rtw_adapter *padapter, u8 msgbox_num)
31 {
32         u8 read_down = false;
33         int     retry_cnts = 100;
34         u8 valid;
35
36         do {
37                 valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num);
38                 if (0 == valid)
39                         read_down = true;
40         } while ((!read_down) && (retry_cnts--));
41
42         return read_down;
43 }
44
45 /*****************************************
46 * H2C Msg format :
47 *| 31 - 8               |7              | 6 - 0 |
48 *| h2c_msg      |Ext_bit        |CMD_ID |
49 *
50 ******************************************/
51 s32 FillH2CCmd(struct rtw_adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
52 {
53         u8 bcmd_down = false;
54         s32 retry_cnts = 100;
55         u8 h2c_box_num;
56         u32 msgbox_addr;
57         u32 msgbox_ex_addr;
58         struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
59         u32 h2c_cmd = 0;
60         u16 h2c_cmd_ex = 0;
61         s32 ret = _FAIL;
62
63         padapter = GET_PRIMARY_ADAPTER(padapter);
64         pHalData = GET_HAL_DATA(padapter);
65
66         mutex_lock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex);
67
68         if (!pCmdBuffer)
69                 goto exit;
70         if (CmdLen > RTL92C_MAX_CMD_LEN)
71                 goto exit;
72         if (padapter->bSurpriseRemoved == true)
73                 goto exit;
74
75         /* pay attention to if  race condition happened in  H2C cmd setting. */
76         do {
77                 h2c_box_num = pHalData->LastHMEBoxNum;
78
79                 if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) {
80                         DBG_8723A(" fw read cmd failed...\n");
81                         goto exit;
82                 }
83
84                 if (CmdLen <= 3) {
85                         memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
86                 } else {
87                         memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer, EX_MESSAGE_BOX_SIZE);
88                         memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer+2, (CmdLen-EX_MESSAGE_BOX_SIZE));
89                         *(u8 *)(&h2c_cmd) |= BIT(7);
90                 }
91
92                 *(u8 *)(&h2c_cmd) |= ElementID;
93
94                 if (h2c_cmd & BIT(7)) {
95                         msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * EX_MESSAGE_BOX_SIZE);
96                         h2c_cmd_ex = le16_to_cpu(h2c_cmd_ex);
97                         rtw_write16(padapter, msgbox_ex_addr, h2c_cmd_ex);
98                 }
99                 msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * MESSAGE_BOX_SIZE);
100                 h2c_cmd = le32_to_cpu(h2c_cmd);
101                 rtw_write32(padapter, msgbox_addr, h2c_cmd);
102
103                 bcmd_down = true;
104
105                 pHalData->LastHMEBoxNum = (h2c_box_num+1) % RTL92C_MAX_H2C_BOX_NUMS;
106
107         } while ((!bcmd_down) && (retry_cnts--));
108
109         ret = _SUCCESS;
110
111 exit:
112         mutex_unlock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex);
113         return ret;
114 }
115
116 u8 rtl8723a_set_rssi_cmd(struct rtw_adapter *padapter, u8 *param)
117 {
118         u8 res = _SUCCESS;
119
120         *((u32 *)param) = cpu_to_le32(*((u32 *)param));
121
122         FillH2CCmd(padapter, RSSI_SETTING_EID, 3, param);
123
124         return res;
125 }
126
127 u8 rtl8723a_set_raid_cmd(struct rtw_adapter *padapter, u32 mask, u8 arg)
128 {
129         u8 buf[5];
130         u8 res = _SUCCESS;
131
132         memset(buf, 0, 5);
133         mask = cpu_to_le32(mask);
134         memcpy(buf, &mask, 4);
135         buf[4]  = arg;
136
137         FillH2CCmd(padapter, MACID_CONFIG_EID, 5, buf);
138
139         return res;
140
141 }
142
143 /* bitmap[0:27] = tx_rate_bitmap */
144 /* bitmap[28:31]= Rate Adaptive id */
145 /* arg[0:4] = macid */
146 /* arg[5] = Short GI */
147 void rtl8723a_add_rateatid(struct rtw_adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level)
148 {
149         struct hal_data_8723a   *pHalData = GET_HAL_DATA(pAdapter);
150         u8 macid = arg&0x1f;
151         u8 raid = (bitmap>>28) & 0x0f;
152
153         bitmap &= 0x0fffffff;
154         if (rssi_level != DM_RATR_STA_INIT)
155                 bitmap = ODM_Get_Rate_Bitmap23a(&pHalData->odmpriv, macid, bitmap, rssi_level);
156
157         bitmap |= ((raid<<28)&0xf0000000);
158
159         if (pHalData->fw_ractrl == true) {
160                 rtl8723a_set_raid_cmd(pAdapter, bitmap, arg);
161         } else {
162                 u8 init_rate, shortGIrate = false;
163
164                 init_rate = get_highest_rate_idx23a(bitmap&0x0fffffff)&0x3f;
165
166                 shortGIrate = (arg&BIT(5)) ? true:false;
167
168                 if (shortGIrate == true)
169                         init_rate |= BIT(6);
170
171                 rtw_write8(pAdapter, (REG_INIDATA_RATE_SEL+macid), (u8)init_rate);
172         }
173 }
174
175 void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter *padapter, u8 Mode)
176 {
177         struct setpwrmode_parm H2CSetPwrMode;
178         struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
179         struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
180
181         DBG_8723A("%s: Mode =%d SmartPS =%d UAPSD =%d BcnMode = 0x%02x\n", __FUNCTION__,
182                         Mode, pwrpriv->smart_ps, padapter->registrypriv.uapsd_enable, pwrpriv->bcn_ant_mode);
183
184         /*  Forece leave RF low power mode for 1T1R to
185             prevent conficting setting in Fw power */
186         /*  saving sequence. 2010.06.07. Added by tynli.
187             Suggested by SD3 yschang. */
188         if ((Mode != PS_MODE_ACTIVE) &&
189             (!IS_92C_SERIAL(pHalData->VersionID))) {
190                 ODM_RF_Saving23a(&pHalData->odmpriv, true);
191         }
192
193         H2CSetPwrMode.Mode = Mode;
194         H2CSetPwrMode.SmartPS = pwrpriv->smart_ps;
195         H2CSetPwrMode.AwakeInterval = 1;
196         H2CSetPwrMode.bAllQueueUAPSD = padapter->registrypriv.uapsd_enable;
197         H2CSetPwrMode.BcnAntMode = pwrpriv->bcn_ant_mode;
198
199         FillH2CCmd(padapter, SET_PWRMODE_EID, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
200
201 }
202
203 static void ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength)
204 {
205         struct ieee80211_hdr *pwlanhdr;
206         u16 *fctrl;
207         u32 rate_len, pktlen;
208         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
209         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
210         struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
211         u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
212
213         /* DBG_8723A("%s\n", __FUNCTION__); */
214
215         pwlanhdr = (struct ieee80211_hdr *)pframe;
216
217         fctrl = &pwlanhdr->frame_control;
218         *(fctrl) = 0;
219
220         memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
221         memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
222         memcpy(pwlanhdr->addr3, get_my_bssid23a(cur_network), ETH_ALEN);
223
224         SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
225         /* pmlmeext->mgnt_seq++; */
226         SetFrameSubType(pframe, WIFI_BEACON);
227
228         pframe += sizeof(struct ieee80211_hdr_3addr);
229         pktlen = sizeof (struct ieee80211_hdr_3addr);
230
231         /* timestamp will be inserted by hardware */
232         pframe += 8;
233         pktlen += 8;
234
235         /*  beacon interval: 2 bytes */
236         memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval23a_from_ie(cur_network->IEs)), 2);
237
238         pframe += 2;
239         pktlen += 2;
240
241         /*  capability info: 2 bytes */
242         memcpy(pframe, (unsigned char *)(rtw_get_capability23a_from_ie(cur_network->IEs)), 2);
243
244         pframe += 2;
245         pktlen += 2;
246
247         if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
248                 /* DBG_8723A("ie len =%d\n", cur_network->IELength); */
249                 pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ies);
250                 memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fixed_ies), pktlen);
251
252                 goto _ConstructBeacon;
253         }
254
255         /* below for ad-hoc mode */
256
257         /*  SSID */
258         pframe = rtw_set_ie23a(pframe, _SSID_IE_, cur_network->Ssid.ssid_len,
259                             cur_network->Ssid.ssid, &pktlen);
260
261         /*  supported rates... */
262         rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
263         pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ?
264                                8 : rate_len), cur_network->SupportedRates, &pktlen);
265
266         /*  DS parameter set */
267         pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)&cur_network->Configuration.DSConfig, &pktlen);
268
269         if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
270                 u32 ATIMWindow;
271                 /*  IBSS Parameter Set... */
272                 /* ATIMWindow = cur->Configuration.ATIMWindow; */
273                 ATIMWindow = 0;
274                 pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen);
275         }
276
277         /* todo: ERP IE */
278
279         /*  EXTERNDED SUPPORTED RATE */
280         if (rate_len > 8)
281                 pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen);
282
283         /* todo:HT for adhoc */
284
285 _ConstructBeacon:
286
287         if ((pktlen + TXDESC_SIZE) > 512) {
288                 DBG_8723A("beacon frame too large\n");
289                 return;
290         }
291
292         *pLength = pktlen;
293
294         /* DBG_8723A("%s bcn_sz =%d\n", __FUNCTION__, pktlen); */
295
296 }
297
298 static void ConstructPSPoll(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength)
299 {
300         struct ieee80211_hdr *pwlanhdr;
301         u16 *fctrl;
302         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
303         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
304
305         pwlanhdr = (struct ieee80211_hdr *)pframe;
306
307         /*  Frame control. */
308         fctrl = &pwlanhdr->frame_control;
309         *(fctrl) = 0;
310         SetPwrMgt(fctrl);
311         SetFrameSubType(pframe, WIFI_PSPOLL);
312
313         /*  AID. */
314         SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
315
316         /*  BSSID. */
317         memcpy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
318
319         /*  TA. */
320         memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
321
322         *pLength = 16;
323 }
324
325 static void ConstructNullFunctionData(
326         struct rtw_adapter *padapter,
327         u8 *pframe,
328         u32 *pLength,
329         u8 *StaAddr,
330         u8 bQoS,
331         u8 AC,
332         u8 bEosp,
333         u8 bForcePowerSave)
334 {
335         struct ieee80211_hdr *pwlanhdr;
336         u16 *fctrl;
337         u32 pktlen;
338         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
339         struct wlan_network             *cur_network = &pmlmepriv->cur_network;
340         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
341         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
342
343         pwlanhdr = (struct ieee80211_hdr *)pframe;
344
345         fctrl = &pwlanhdr->frame_control;
346         *(fctrl) = 0;
347         if (bForcePowerSave)
348                 SetPwrMgt(fctrl);
349
350         switch (cur_network->network.InfrastructureMode) {
351         case Ndis802_11Infrastructure:
352                 SetToDs(fctrl);
353                 memcpy(pwlanhdr->addr1,
354                        get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
355                 memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv),
356                        ETH_ALEN);
357                 memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
358                 break;
359         case Ndis802_11APMode:
360                 SetFrDs(fctrl);
361                 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
362                 memcpy(pwlanhdr->addr2,
363                        get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
364                 memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv),
365                        ETH_ALEN);
366                 break;
367         case Ndis802_11IBSS:
368         default:
369                 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
370                 memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
371                 memcpy(pwlanhdr->addr3,
372                        get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
373                 break;
374         }
375
376         SetSeqNum(pwlanhdr, 0);
377
378         if (bQoS == true) {
379                 struct ieee80211_qos_hdr *pwlanqoshdr;
380
381                 SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
382
383                 pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe;
384                 SetPriority(&pwlanqoshdr->qos_ctrl, AC);
385                 SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp);
386
387                 pktlen = sizeof(struct ieee80211_qos_hdr);
388         } else {
389                 SetFrameSubType(pframe, WIFI_DATA_NULL);
390
391                 pktlen = sizeof(struct ieee80211_hdr_3addr);
392         }
393
394         *pLength = pktlen;
395 }
396
397 static void ConstructProbeRsp(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID)
398 {
399         struct ieee80211_hdr *pwlanhdr;
400         u16 *fctrl;
401         u8 *mac, *bssid;
402         u32 pktlen;
403         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
404         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
405         struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
406
407         /* DBG_8723A("%s\n", __FUNCTION__); */
408
409         pwlanhdr = (struct ieee80211_hdr *)pframe;
410
411         mac = myid(&padapter->eeprompriv);
412         bssid = cur_network->MacAddress;
413
414         fctrl = &pwlanhdr->frame_control;
415         *(fctrl) = 0;
416         memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
417         memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
418         memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
419
420         SetSeqNum(pwlanhdr, 0);
421         SetFrameSubType(fctrl, WIFI_PROBERSP);
422
423         pktlen = sizeof(struct ieee80211_hdr_3addr);
424         pframe += pktlen;
425
426         if (cur_network->IELength > MAX_IE_SZ)
427                 return;
428
429         memcpy(pframe, cur_network->IEs, cur_network->IELength);
430         pframe += cur_network->IELength;
431         pktlen += cur_network->IELength;
432
433         *pLength = pktlen;
434 }
435
436 /*  To check if reserved page content is destroyed by beacon beacuse beacon is too large. */
437 void CheckFwRsvdPageContent23a(struct rtw_adapter *Adapter)
438 {
439 }
440
441 /*  */
442 /*  Description: Fill the reserved packets that FW will use to RSVD page. */
443 /*                      Now we just send 4 types packet to rsvd page. */
444 /*                      (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
445 /*      Input: */
446 /*          bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
447 /*                                              so we need to set the packet length to total lengh. */
448 /*                            true: At the second time, we should send the first packet (default:beacon) */
449 /*                                              to Hw again and set the lengh in descriptor to the real beacon lengh. */
450 /*  2009.10.15 by tynli. */
451 static void SetFwRsvdPagePkt(struct rtw_adapter *padapter, bool bDLFinished)
452 {
453         struct hal_data_8723a *pHalData;
454         struct xmit_frame *pmgntframe;
455         struct pkt_attrib *pattrib;
456         struct xmit_priv *pxmitpriv;
457         struct mlme_ext_priv *pmlmeext;
458         struct mlme_ext_info *pmlmeinfo;
459         u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength;
460         u32 NullDataLength, QosNullLength, BTQosNullLength;
461         u8 *ReservedPagePacket;
462         u8 PageNum, PageNeed, TxDescLen;
463         u16 BufIndex;
464         u32 TotalPacketLen;
465         struct rsvdpage_loc     RsvdPageLoc;
466
467         DBG_8723A("%s\n", __FUNCTION__);
468
469         ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
470         if (ReservedPagePacket == NULL) {
471                 DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__);
472                 return;
473         }
474
475         pHalData = GET_HAL_DATA(padapter);
476         pxmitpriv = &padapter->xmitpriv;
477         pmlmeext = &padapter->mlmeextpriv;
478         pmlmeinfo = &pmlmeext->mlmext_info;
479
480         TxDescLen = TXDESC_SIZE;
481         PageNum = 0;
482
483         /* 3 (1) beacon */
484         BufIndex = TXDESC_OFFSET;
485         ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
486
487         /*  When we count the first page size, we need to reserve description size for the RSVD */
488         /*  packet, it will be filled in front of the packet in TXPKTBUF. */
489         PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength);
490         /*  To reserved 2 pages for beacon buffer. 2010.06.24. */
491         if (PageNeed == 1)
492                 PageNeed += 1;
493         PageNum += PageNeed;
494         pHalData->FwRsvdPageStartOffset = PageNum;
495
496         BufIndex += PageNeed*128;
497
498         /* 3 (2) ps-poll */
499         RsvdPageLoc.LocPsPoll = PageNum;
500         ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength);
501         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
502
503         PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
504         PageNum += PageNeed;
505
506         BufIndex += PageNeed*128;
507
508         /* 3 (3) null data */
509         RsvdPageLoc.LocNullData = PageNum;
510         ConstructNullFunctionData(
511                 padapter,
512                 &ReservedPagePacket[BufIndex],
513                 &NullDataLength,
514                 get_my_bssid23a(&pmlmeinfo->network),
515                 false, 0, 0, false);
516         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
517
518         PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
519         PageNum += PageNeed;
520
521         BufIndex += PageNeed*128;
522
523         /* 3 (4) probe response */
524         RsvdPageLoc.LocProbeRsp = PageNum;
525         ConstructProbeRsp(
526                 padapter,
527                 &ReservedPagePacket[BufIndex],
528                 &ProbeRspLength,
529                 get_my_bssid23a(&pmlmeinfo->network),
530                 false);
531         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
532
533         PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
534         PageNum += PageNeed;
535
536         BufIndex += PageNeed*128;
537
538         /* 3 (5) Qos null data */
539         RsvdPageLoc.LocQosNull = PageNum;
540         ConstructNullFunctionData(
541                 padapter,
542                 &ReservedPagePacket[BufIndex],
543                 &QosNullLength,
544                 get_my_bssid23a(&pmlmeinfo->network),
545                 true, 0, 0, false);
546         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
547
548         PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
549         PageNum += PageNeed;
550
551         BufIndex += PageNeed*128;
552
553         /* 3 (6) BT Qos null data */
554         RsvdPageLoc.LocBTQosNull = PageNum;
555         ConstructNullFunctionData(
556                 padapter,
557                 &ReservedPagePacket[BufIndex],
558                 &BTQosNullLength,
559                 get_my_bssid23a(&pmlmeinfo->network),
560                 true, 0, 0, false);
561         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
562
563         TotalPacketLen = BufIndex + BTQosNullLength;
564
565         pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
566         if (pmgntframe == NULL)
567                 goto exit;
568
569         /*  update attribute */
570         pattrib = &pmgntframe->attrib;
571         update_mgntframe_attrib23a(padapter, pattrib);
572         pattrib->qsel = 0x10;
573         pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
574         memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
575
576         rtw_hal_mgnt_xmit23a(padapter, pmgntframe);
577
578         DBG_8723A("%s: Set RSVD page location to Fw\n", __FUNCTION__);
579         FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
580
581 exit:
582         kfree(ReservedPagePacket);
583 }
584
585 void rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter *padapter, u8 mstatus)
586 {
587         struct joinbssrpt_parm  JoinBssRptParm;
588         struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
589         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
590         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
591
592         DBG_8723A("%s mstatus(%x)\n", __FUNCTION__, mstatus);
593
594         if (mstatus == 1) {
595                 bool bRecover = false;
596                 u8 v8;
597
598                 /*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
599                 /*  Suggested by filen. Added by tynli. */
600                 rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
601                 /*  Do not set TSF again here or vWiFi beacon DMA INT will not work. */
602                 /* correct_TSF23a(padapter, pmlmeext); */
603                 /*  Hw sequende enable by dedault. 2010.06.23. by tynli. */
604                 /* rtw_write16(padapter, REG_NQOS_SEQ, ((pmlmeext->mgnt_seq+100)&0xFFF)); */
605                 /* rtw_write8(padapter, REG_HWSEQ_CTRL, 0xFF); */
606
607                 /*  set REG_CR bit 8 */
608                 v8 = rtw_read8(padapter, REG_CR+1);
609                 v8 |= BIT(0); /*  ENSWBCN */
610                 rtw_write8(padapter,  REG_CR+1, v8);
611
612                 /*  Disable Hw protection for a time which revserd for Hw sending beacon. */
613                 /*  Fix download reserved page packet fail that access collision with the protection time. */
614                 /*  2010.05.11. Added by tynli. */
615 /*                      SetBcnCtrlReg23a(padapter, 0, BIT(3)); */
616 /*                      SetBcnCtrlReg23a(padapter, BIT(4), 0); */
617                 SetBcnCtrlReg23a(padapter, BIT(4), BIT(3));
618
619                 /*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
620                 if (pHalData->RegFwHwTxQCtrl & BIT(6))
621                         bRecover = true;
622
623                 /*  To tell Hw the packet is not a real beacon frame. */
624                 /* U1bTmp = rtw_read8(padapter, REG_FWHW_TXQ_CTRL+2); */
625                 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6));
626                 pHalData->RegFwHwTxQCtrl &= ~BIT(6);
627                 SetFwRsvdPagePkt(padapter, 0);
628
629                 /*  2010.05.11. Added by tynli. */
630                 SetBcnCtrlReg23a(padapter, BIT(3), BIT(4));
631
632                 /*  To make sure that if there exists an adapter which would like to send beacon. */
633                 /*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
634                 /*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
635                 /*  the beacon cannot be sent by HW. */
636                 /*  2010.06.23. Added by tynli. */
637                 if (bRecover) {
638                         rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6));
639                         pHalData->RegFwHwTxQCtrl |= BIT(6);
640                 }
641
642                 /*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
643                 v8 = rtw_read8(padapter, REG_CR+1);
644                 v8 &= ~BIT(0); /*  ~ENSWBCN */
645                 rtw_write8(padapter, REG_CR+1, v8);
646         }
647
648         JoinBssRptParm.OpMode = mstatus;
649
650         FillH2CCmd(padapter, JOINBSS_RPT_EID, sizeof(JoinBssRptParm), (u8 *)&JoinBssRptParm);
651
652 }
653
654 #ifdef CONFIG_8723AU_BT_COEXIST
655 static void SetFwRsvdPagePkt_BTCoex(struct rtw_adapter *padapter)
656 {
657         struct hal_data_8723a *pHalData;
658         struct xmit_frame *pmgntframe;
659         struct pkt_attrib *pattrib;
660         struct xmit_priv *pxmitpriv;
661         struct mlme_ext_priv *pmlmeext;
662         struct mlme_ext_info *pmlmeinfo;
663         u8 fakemac[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x00};
664         u32 NullDataLength, BTQosNullLength;
665         u8 *ReservedPagePacket;
666         u8 PageNum, PageNeed, TxDescLen;
667         u16 BufIndex;
668         u32 TotalPacketLen;
669         struct rsvdpage_loc     RsvdPageLoc;
670
671         DBG_8723A("+%s\n", __FUNCTION__);
672
673         ReservedPagePacket = kzalloc(1024, GFP_KERNEL);
674         if (ReservedPagePacket == NULL) {
675                 DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__);
676                 return;
677         }
678
679         pHalData = GET_HAL_DATA(padapter);
680         pxmitpriv = &padapter->xmitpriv;
681         pmlmeext = &padapter->mlmeextpriv;
682         pmlmeinfo = &pmlmeext->mlmext_info;
683
684         TxDescLen = TXDESC_SIZE;
685         PageNum = 0;
686
687         /* 3 (1) beacon */
688         BufIndex = TXDESC_OFFSET;
689         /*  skip Beacon Packet */
690         PageNeed = 3;
691
692         PageNum += PageNeed;
693         pHalData->FwRsvdPageStartOffset = PageNum;
694
695         BufIndex += PageNeed*128;
696
697         /* 3 (3) null data */
698         RsvdPageLoc.LocNullData = PageNum;
699         ConstructNullFunctionData(
700                 padapter,
701                 &ReservedPagePacket[BufIndex],
702                 &NullDataLength,
703                 fakemac,
704                 false, 0, 0, false);
705         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
706
707         PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
708         PageNum += PageNeed;
709
710         BufIndex += PageNeed*128;
711
712         /* 3 (6) BT Qos null data */
713         RsvdPageLoc.LocBTQosNull = PageNum;
714         ConstructNullFunctionData(
715                 padapter,
716                 &ReservedPagePacket[BufIndex],
717                 &BTQosNullLength,
718                 fakemac,
719                 true, 0, 0, false);
720         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
721
722         TotalPacketLen = BufIndex + BTQosNullLength;
723
724         pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
725         if (pmgntframe == NULL)
726                 goto exit;
727
728         /*  update attribute */
729         pattrib = &pmgntframe->attrib;
730         update_mgntframe_attrib23a(padapter, pattrib);
731         pattrib->qsel = 0x10;
732         pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
733         memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
734
735         rtw_hal_mgnt_xmit23a(padapter, pmgntframe);
736
737         DBG_8723A("%s: Set RSVD page location to Fw\n", __FUNCTION__);
738         FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
739
740 exit:
741         kfree(ReservedPagePacket);
742 }
743
744 void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter *padapter)
745 {
746         struct hal_data_8723a *pHalData;
747         u8 bRecover = false;
748
749         DBG_8723A("+%s\n", __FUNCTION__);
750
751         pHalData = GET_HAL_DATA(padapter);
752
753         /*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
754         if (pHalData->RegFwHwTxQCtrl & BIT(6))
755                 bRecover = true;
756
757         /*  To tell Hw the packet is not a real beacon frame. */
758         pHalData->RegFwHwTxQCtrl &= ~BIT(6);
759         rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
760         SetFwRsvdPagePkt_BTCoex(padapter);
761
762         /*  To make sure that if there exists an adapter which would like to send beacon. */
763         /*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
764         /*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
765         /*  the beacon cannot be sent by HW. */
766         /*  2010.06.23. Added by tynli. */
767         if (bRecover) {
768                 pHalData->RegFwHwTxQCtrl |= BIT(6);
769                 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
770         }
771 }
772 #endif
773
774 #ifdef CONFIG_8723AU_P2P
775 void rtl8723a_set_p2p_ps_offload_cmd(struct rtw_adapter *padapter, u8 p2p_ps_state)
776 {
777         struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
778         struct wifidirect_info *pwdinfo = &padapter->wdinfo;
779         struct P2P_PS_Offload_t *p2p_ps_offload = &pHalData->p2p_ps_offload;
780         u8 i;
781
782         switch (p2p_ps_state) {
783         case P2P_PS_DISABLE:
784                 DBG_8723A("P2P_PS_DISABLE \n");
785                 memset(p2p_ps_offload, 0, 1);
786                 break;
787         case P2P_PS_ENABLE:
788                 DBG_8723A("P2P_PS_ENABLE \n");
789                 /*  update CTWindow value. */
790                 if (pwdinfo->ctwindow > 0) {
791                         p2p_ps_offload->CTWindow_En = 1;
792                         rtw_write8(padapter, REG_P2P_CTWIN, pwdinfo->ctwindow);
793                 }
794
795                 /*  hw only support 2 set of NoA */
796                 for (i = 0; i < pwdinfo->noa_num; i++) {
797                         /*  To control the register setting for which NOA */
798                         rtw_write8(padapter, REG_NOA_DESC_SEL, (i << 4));
799                         if (i == 0)
800                                 p2p_ps_offload->NoA0_En = 1;
801                         else
802                                 p2p_ps_offload->NoA1_En = 1;
803
804                         /*  config P2P NoA Descriptor Register */
805                         rtw_write32(padapter, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]);
806
807                         rtw_write32(padapter, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]);
808
809                         rtw_write32(padapter, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]);
810
811                         rtw_write8(padapter, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]);
812                 }
813
814                 if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) {
815                         /*  rst p2p circuit */
816                         rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(4));
817
818                         p2p_ps_offload->Offload_En = 1;
819
820                         if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
821                                 p2p_ps_offload->role = 1;
822                                 p2p_ps_offload->AllStaSleep = 0;
823                         } else {
824                                 p2p_ps_offload->role = 0;
825                         }
826
827                         p2p_ps_offload->discovery = 0;
828                 }
829                 break;
830         case P2P_PS_SCAN:
831                 DBG_8723A("P2P_PS_SCAN \n");
832                 p2p_ps_offload->discovery = 1;
833                 break;
834         case P2P_PS_SCAN_DONE:
835                 DBG_8723A("P2P_PS_SCAN_DONE \n");
836                 p2p_ps_offload->discovery = 0;
837                 pwdinfo->p2p_ps_state = P2P_PS_ENABLE;
838                 break;
839         default:
840                 break;
841         }
842
843         FillH2CCmd(padapter, P2P_PS_OFFLOAD_EID, 1, (u8 *)p2p_ps_offload);
844 }
845 #endif /* CONFIG_8723AU_P2P */