These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / 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 <mlme_osdep.h>
21 #include <rtl8723a_hal.h>
22 #include <usb_ops_linux.h>
23
24 #define RTL92C_MAX_H2C_BOX_NUMS         4
25 #define RTL92C_MAX_CMD_LEN              5
26 #define MESSAGE_BOX_SIZE                4
27 #define EX_MESSAGE_BOX_SIZE             2
28
29 static u8 _is_fw_read_cmd_down(struct rtw_adapter *padapter, u8 msgbox_num)
30 {
31         u8 read_down = false;
32         int     retry_cnts = 100;
33         u8 valid;
34
35         do {
36                 valid = rtl8723au_read8(padapter, REG_HMETFR) & BIT(msgbox_num);
37                 if (0 == valid)
38                         read_down = true;
39         } while ((!read_down) && (retry_cnts--));
40
41         return read_down;
42 }
43
44 /*****************************************
45 * H2C Msg format :
46 *| 31 - 8               |7              | 6 - 0 |
47 *| h2c_msg      |Ext_bit        |CMD_ID |
48 *
49 ******************************************/
50 int FillH2CCmd(struct rtw_adapter *padapter, u8 ElementID, u32 CmdLen,
51                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;
59         u32 h2c_cmd = 0;
60         u16 h2c_cmd_ex = 0;
61         int 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                         rtl8723au_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                 rtl8723au_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 int rtl8723a_set_rssi_cmd(struct rtw_adapter *padapter, u8 *param)
117 {
118         *((u32 *)param) = cpu_to_le32(*((u32 *)param));
119
120         FillH2CCmd(padapter, RSSI_SETTING_EID, 3, param);
121
122         return _SUCCESS;
123 }
124
125 int rtl8723a_set_raid_cmd(struct rtw_adapter *padapter, u32 mask, u8 arg)
126 {
127         u8 buf[5];
128
129         memset(buf, 0, 5);
130         put_unaligned_le32(mask, buf);
131         buf[4]  = arg;
132
133         FillH2CCmd(padapter, MACID_CONFIG_EID, 5, buf);
134
135         return _SUCCESS;
136 }
137
138 /* bitmap[0:27] = tx_rate_bitmap */
139 /* bitmap[28:31]= Rate Adaptive id */
140 /* arg[0:4] = macid */
141 /* arg[5] = Short GI */
142 void rtl8723a_add_rateatid(struct rtw_adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level)
143 {
144         struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
145         u8 macid = arg & 0x1f;
146         u32 raid = bitmap & 0xf0000000;
147
148         bitmap &= 0x0fffffff;
149         if (rssi_level != DM_RATR_STA_INIT)
150                 bitmap = ODM_Get_Rate_Bitmap23a(pHalData, macid, bitmap,
151                                                 rssi_level);
152
153         bitmap |= raid;
154
155         rtl8723a_set_raid_cmd(pAdapter, bitmap, arg);
156 }
157
158 void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter *padapter, u8 Mode)
159 {
160         struct setpwrmode_parm H2CSetPwrMode;
161         struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
162         struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
163
164         DBG_8723A("%s: Mode =%d SmartPS =%d UAPSD =%d BcnMode = 0x%02x\n", __func__,
165                         Mode, pwrpriv->smart_ps, padapter->registrypriv.uapsd_enable, pwrpriv->bcn_ant_mode);
166
167         /*  Forece leave RF low power mode for 1T1R to
168             prevent conficting setting in Fw power */
169         /*  saving sequence. 2010.06.07. Added by tynli.
170             Suggested by SD3 yschang. */
171         if (Mode != PS_MODE_ACTIVE && pHalData->rf_type != RF_2T2R)
172                 ODM_RF_Saving23a(&pHalData->odmpriv, true);
173
174         H2CSetPwrMode.Mode = Mode;
175         H2CSetPwrMode.SmartPS = pwrpriv->smart_ps;
176         H2CSetPwrMode.AwakeInterval = 1;
177         H2CSetPwrMode.bAllQueueUAPSD = padapter->registrypriv.uapsd_enable;
178         H2CSetPwrMode.BcnAntMode = pwrpriv->bcn_ant_mode;
179
180         FillH2CCmd(padapter, SET_PWRMODE_EID, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
181
182 }
183
184 static void
185 ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength)
186 {
187         struct ieee80211_mgmt *mgmt;
188         u32 rate_len, pktlen;
189         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
190         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
191         struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
192         u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
193
194         /* DBG_8723A("%s\n", __func__); */
195
196         mgmt = (struct ieee80211_mgmt *)pframe;
197
198         mgmt->frame_control =
199                 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
200
201         ether_addr_copy(mgmt->da, bc_addr);
202         ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
203         ether_addr_copy(mgmt->bssid, get_my_bssid23a(cur_network));
204
205         /* A Beacon frame shouldn't have fragment bits set */
206         mgmt->seq_ctrl = 0;
207
208         /* timestamp will be inserted by hardware */
209
210         put_unaligned_le16(cur_network->beacon_interval,
211                            &mgmt->u.beacon.beacon_int);
212
213         put_unaligned_le16(cur_network->capability,
214                            &mgmt->u.beacon.capab_info);
215
216         pframe = mgmt->u.beacon.variable;
217         pktlen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
218
219         if ((pmlmeinfo->state&0x03) == MSR_AP) {
220                 /* DBG_8723A("ie len =%d\n", cur_network->IELength); */
221                 pktlen += cur_network->IELength;
222                 memcpy(pframe, cur_network->IEs, pktlen);
223
224                 goto _ConstructBeacon;
225         }
226
227         /* below for ad-hoc mode */
228
229         /*  SSID */
230         pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID,
231                                cur_network->Ssid.ssid_len,
232                                cur_network->Ssid.ssid, &pktlen);
233
234         /*  supported rates... */
235         rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
236         pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ?
237                                8 : rate_len), cur_network->SupportedRates, &pktlen);
238
239         /*  DS parameter set */
240         pframe = rtw_set_ie23a(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)
241                                &cur_network->DSConfig, &pktlen);
242
243         if ((pmlmeinfo->state&0x03) == MSR_ADHOC) {
244                 u32 ATIMWindow;
245                 /*  IBSS Parameter Set... */
246                 /* ATIMWindow = cur->ATIMWindow; */
247                 ATIMWindow = 0;
248                 pframe = rtw_set_ie23a(pframe, WLAN_EID_IBSS_PARAMS, 2,
249                                        (unsigned char *)&ATIMWindow, &pktlen);
250         }
251
252         /* todo: ERP IE */
253
254         /*  EXTERNDED SUPPORTED RATE */
255         if (rate_len > 8)
256                 pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES,
257                                        (rate_len - 8),
258                                        (cur_network->SupportedRates + 8),
259                                        &pktlen);
260
261         /* todo:HT for adhoc */
262
263 _ConstructBeacon:
264
265         if ((pktlen + TXDESC_SIZE) > 512) {
266                 DBG_8723A("beacon frame too large\n");
267                 return;
268         }
269
270         *pLength = pktlen;
271
272         /* DBG_8723A("%s bcn_sz =%d\n", __func__, pktlen); */
273
274 }
275
276 static void ConstructPSPoll(struct rtw_adapter *padapter,
277                             u8 *pframe, u32 *pLength)
278 {
279         struct ieee80211_hdr *pwlanhdr;
280         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
281         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
282
283         pwlanhdr = (struct ieee80211_hdr *)pframe;
284
285         /*  Frame control. */
286         pwlanhdr->frame_control =
287                 cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
288         pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
289
290         /*  AID. */
291         pwlanhdr->duration_id = cpu_to_le16(pmlmeinfo->aid | 0xc000);
292
293         /*  BSSID. */
294         memcpy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
295
296         /*  TA. */
297         memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
298
299         *pLength = 16;
300 }
301
302 static void
303 ConstructNullFunctionData(struct rtw_adapter *padapter, u8 *pframe,
304                           u32 *pLength, u8 *StaAddr, u8 bQoS, u8 AC,
305                           u8 bEosp, u8 bForcePowerSave)
306 {
307         struct ieee80211_hdr *pwlanhdr;
308         u32 pktlen;
309         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
310         struct wlan_network *cur_network = &pmlmepriv->cur_network;
311         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
312         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
313
314         pwlanhdr = (struct ieee80211_hdr *)pframe;
315
316         pwlanhdr->frame_control = 0;
317         pwlanhdr->seq_ctrl = 0;
318
319         if (bForcePowerSave)
320                 pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
321
322         switch (cur_network->network.ifmode) {
323         case NL80211_IFTYPE_P2P_CLIENT:
324         case NL80211_IFTYPE_STATION:
325                 pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS);
326                 memcpy(pwlanhdr->addr1,
327                        get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
328                 memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv),
329                        ETH_ALEN);
330                 memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
331                 break;
332         case NL80211_IFTYPE_P2P_GO:
333         case NL80211_IFTYPE_AP:
334                 pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
335                 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
336                 memcpy(pwlanhdr->addr2,
337                        get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
338                 memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv),
339                        ETH_ALEN);
340                 break;
341         case NL80211_IFTYPE_ADHOC:
342         default:
343                 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
344                 memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
345                 memcpy(pwlanhdr->addr3,
346                        get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
347                 break;
348         }
349
350         if (bQoS == true) {
351                 struct ieee80211_qos_hdr *qoshdr;
352                 qoshdr = (struct ieee80211_qos_hdr *)pframe;
353
354                 qoshdr->frame_control |=
355                         cpu_to_le16(IEEE80211_FTYPE_DATA |
356                                     IEEE80211_STYPE_QOS_NULLFUNC);
357
358                 qoshdr->qos_ctrl = cpu_to_le16(AC & IEEE80211_QOS_CTL_TID_MASK);
359                 if (bEosp)
360                         qoshdr->qos_ctrl |= cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
361
362                 pktlen = sizeof(struct ieee80211_qos_hdr);
363         } else {
364                 pwlanhdr->frame_control |=
365                         cpu_to_le16(IEEE80211_FTYPE_DATA |
366                                     IEEE80211_STYPE_NULLFUNC);
367
368                 pktlen = sizeof(struct ieee80211_hdr_3addr);
369         }
370
371         *pLength = pktlen;
372 }
373
374 static void ConstructProbeRsp(struct rtw_adapter *padapter, u8 *pframe,
375                               u32 *pLength, u8 *StaAddr, bool bHideSSID)
376 {
377         struct ieee80211_mgmt *mgmt;
378         u8 *mac, *bssid;
379         u32 pktlen;
380         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
381         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
382         struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
383
384         /* DBG_8723A("%s\n", __func__); */
385
386         mgmt = (struct ieee80211_mgmt *)pframe;
387
388         mac = myid(&padapter->eeprompriv);
389         bssid = cur_network->MacAddress;
390
391         mgmt->frame_control =
392                 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP);
393
394         mgmt->seq_ctrl = 0;
395
396         memcpy(mgmt->da, StaAddr, ETH_ALEN);
397         memcpy(mgmt->sa, mac, ETH_ALEN);
398         memcpy(mgmt->bssid, bssid, ETH_ALEN);
399
400         put_unaligned_le64(cur_network->tsf,
401                            &mgmt->u.probe_resp.timestamp);
402         put_unaligned_le16(cur_network->beacon_interval,
403                            &mgmt->u.probe_resp.beacon_int);
404         put_unaligned_le16(cur_network->capability,
405                            &mgmt->u.probe_resp.capab_info);
406
407         pktlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
408
409         if (cur_network->IELength > MAX_IE_SZ)
410                 return;
411
412         memcpy(mgmt->u.probe_resp.variable, cur_network->IEs,
413                cur_network->IELength);
414         pktlen += (cur_network->IELength);
415
416         *pLength = pktlen;
417 }
418
419 /*  */
420 /*  Description: Fill the reserved packets that FW will use to RSVD page. */
421 /*                      Now we just send 4 types packet to rsvd page. */
422 /*                      (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
423 /*      Input: */
424 /*          bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
425 /*                                              so we need to set the packet length to total lengh. */
426 /*                            true: At the second time, we should send the first packet (default:beacon) */
427 /*                                              to Hw again and set the lengh in descriptor to the real beacon lengh. */
428 /*  2009.10.15 by tynli. */
429 static void SetFwRsvdPagePkt(struct rtw_adapter *padapter, bool bDLFinished)
430 {
431         struct hal_data_8723a *pHalData;
432         struct xmit_frame *pmgntframe;
433         struct pkt_attrib *pattrib;
434         struct xmit_priv *pxmitpriv;
435         struct mlme_ext_priv *pmlmeext;
436         struct mlme_ext_info *pmlmeinfo;
437         u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength;
438         u32 NullDataLength, QosNullLength, BTQosNullLength;
439         u8 *ReservedPagePacket;
440         u8 PageNum, PageNeed, TxDescLen;
441         u16 BufIndex;
442         u32 TotalPacketLen;
443         struct rsvdpage_loc     RsvdPageLoc;
444
445         DBG_8723A("%s\n", __func__);
446
447         ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
448         if (ReservedPagePacket == NULL) {
449                 DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __func__);
450                 return;
451         }
452
453         pHalData = GET_HAL_DATA(padapter);
454         pxmitpriv = &padapter->xmitpriv;
455         pmlmeext = &padapter->mlmeextpriv;
456         pmlmeinfo = &pmlmeext->mlmext_info;
457
458         TxDescLen = TXDESC_SIZE;
459         PageNum = 0;
460
461         /* 3 (1) beacon */
462         BufIndex = TXDESC_OFFSET;
463         ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
464
465         /*  When we count the first page size, we need to reserve description size for the RSVD */
466         /*  packet, it will be filled in front of the packet in TXPKTBUF. */
467         PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength);
468         /*  To reserved 2 pages for beacon buffer. 2010.06.24. */
469         if (PageNeed == 1)
470                 PageNeed += 1;
471         PageNum += PageNeed;
472         pHalData->FwRsvdPageStartOffset = PageNum;
473
474         BufIndex += PageNeed*128;
475
476         /* 3 (2) ps-poll */
477         RsvdPageLoc.LocPsPoll = PageNum;
478         ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength);
479         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
480
481         PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
482         PageNum += PageNeed;
483
484         BufIndex += PageNeed*128;
485
486         /* 3 (3) null data */
487         RsvdPageLoc.LocNullData = PageNum;
488         ConstructNullFunctionData(padapter, &ReservedPagePacket[BufIndex],
489                                   &NullDataLength,
490                                   get_my_bssid23a(&pmlmeinfo->network),
491                                   false, 0, 0, false);
492         rtl8723a_fill_fake_txdesc(padapter,
493                                   &ReservedPagePacket[BufIndex-TxDescLen],
494                                   NullDataLength, false, false);
495
496         PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
497         PageNum += PageNeed;
498
499         BufIndex += PageNeed*128;
500
501         /* 3 (4) probe response */
502         RsvdPageLoc.LocProbeRsp = PageNum;
503         ConstructProbeRsp(
504                 padapter,
505                 &ReservedPagePacket[BufIndex],
506                 &ProbeRspLength,
507                 get_my_bssid23a(&pmlmeinfo->network),
508                 false);
509         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
510
511         PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
512         PageNum += PageNeed;
513
514         BufIndex += PageNeed*128;
515
516         /* 3 (5) Qos null data */
517         RsvdPageLoc.LocQosNull = PageNum;
518         ConstructNullFunctionData(
519                 padapter,
520                 &ReservedPagePacket[BufIndex],
521                 &QosNullLength,
522                 get_my_bssid23a(&pmlmeinfo->network),
523                 true, 0, 0, false);
524         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
525
526         PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
527         PageNum += PageNeed;
528
529         BufIndex += PageNeed*128;
530
531         /* 3 (6) BT Qos null data */
532         RsvdPageLoc.LocBTQosNull = PageNum;
533         ConstructNullFunctionData(
534                 padapter,
535                 &ReservedPagePacket[BufIndex],
536                 &BTQosNullLength,
537                 get_my_bssid23a(&pmlmeinfo->network),
538                 true, 0, 0, false);
539         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
540
541         TotalPacketLen = BufIndex + BTQosNullLength;
542
543         pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
544         if (pmgntframe == NULL)
545                 goto exit;
546
547         /*  update attribute */
548         pattrib = &pmgntframe->attrib;
549         update_mgntframe_attrib23a(padapter, pattrib);
550         pattrib->qsel = 0x10;
551         pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
552         memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
553
554         rtl8723au_mgnt_xmit(padapter, pmgntframe);
555
556         DBG_8723A("%s: Set RSVD page location to Fw\n", __func__);
557         FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
558
559 exit:
560         kfree(ReservedPagePacket);
561 }
562
563 void rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter *padapter, u8 mstatus)
564 {
565         struct joinbssrpt_parm  JoinBssRptParm;
566         struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
567         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
568         struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
569
570         DBG_8723A("%s mstatus(%x)\n", __func__, mstatus);
571
572         if (mstatus == 1) {
573                 bool bRecover = false;
574                 u8 v8;
575
576                 /*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
577                 /*  Suggested by filen. Added by tynli. */
578                 rtl8723au_write16(padapter, REG_BCN_PSR_RPT,
579                                   0xC000|pmlmeinfo->aid);
580                 /*  Do not set TSF again here or vWiFi beacon DMA INT will not work. */
581                 /* correct_TSF23a(padapter, pmlmeext); */
582                 /*  Hw sequende enable by dedault. 2010.06.23. by tynli. */
583                 /* rtl8723au_write16(padapter, REG_NQOS_SEQ, ((pmlmeext->mgnt_seq+100)&0xFFF)); */
584                 /* rtl8723au_write8(padapter, REG_HWSEQ_CTRL, 0xFF); */
585
586                 /*  set REG_CR bit 8 */
587                 v8 = rtl8723au_read8(padapter, REG_CR+1);
588                 v8 |= BIT(0); /*  ENSWBCN */
589                 rtl8723au_write8(padapter,  REG_CR+1, v8);
590
591                 /*  Disable Hw protection for a time which revserd for Hw sending beacon. */
592                 /*  Fix download reserved page packet fail that access collision with the protection time. */
593                 /*  2010.05.11. Added by tynli. */
594 /*                      SetBcnCtrlReg23a(padapter, 0, BIT(3)); */
595 /*                      SetBcnCtrlReg23a(padapter, BIT(4), 0); */
596                 SetBcnCtrlReg23a(padapter, BIT(4), BIT(3));
597
598                 /*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
599                 if (pHalData->RegFwHwTxQCtrl & BIT(6))
600                         bRecover = true;
601
602                 /*  To tell Hw the packet is not a real beacon frame. */
603                 /* U1bTmp = rtl8723au_read8(padapter, REG_FWHW_TXQ_CTRL+2); */
604                 rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
605                                  pHalData->RegFwHwTxQCtrl & ~BIT(6));
606                 pHalData->RegFwHwTxQCtrl &= ~BIT(6);
607                 SetFwRsvdPagePkt(padapter, 0);
608
609                 /*  2010.05.11. Added by tynli. */
610                 SetBcnCtrlReg23a(padapter, BIT(3), BIT(4));
611
612                 /*  To make sure that if there exists an adapter which would like to send beacon. */
613                 /*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
614                 /*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
615                 /*  the beacon cannot be sent by HW. */
616                 /*  2010.06.23. Added by tynli. */
617                 if (bRecover) {
618                         rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
619                                          pHalData->RegFwHwTxQCtrl | BIT(6));
620                         pHalData->RegFwHwTxQCtrl |= BIT(6);
621                 }
622
623                 /*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
624                 v8 = rtl8723au_read8(padapter, REG_CR+1);
625                 v8 &= ~BIT(0); /*  ~ENSWBCN */
626                 rtl8723au_write8(padapter, REG_CR+1, v8);
627         }
628
629         JoinBssRptParm.OpMode = mstatus;
630
631         FillH2CCmd(padapter, JOINBSS_RPT_EID, sizeof(JoinBssRptParm), (u8 *)&JoinBssRptParm);
632
633 }
634
635 #ifdef CONFIG_8723AU_BT_COEXIST
636 static void SetFwRsvdPagePkt_BTCoex(struct rtw_adapter *padapter)
637 {
638         struct hal_data_8723a *pHalData;
639         struct xmit_frame *pmgntframe;
640         struct pkt_attrib *pattrib;
641         struct xmit_priv *pxmitpriv;
642         struct mlme_ext_priv *pmlmeext;
643         struct mlme_ext_info *pmlmeinfo;
644         u8 fakemac[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x00};
645         u32 NullDataLength, BTQosNullLength;
646         u8 *ReservedPagePacket;
647         u8 PageNum, PageNeed, TxDescLen;
648         u16 BufIndex;
649         u32 TotalPacketLen;
650         struct rsvdpage_loc     RsvdPageLoc;
651
652         DBG_8723A("+%s\n", __func__);
653
654         ReservedPagePacket = kzalloc(1024, GFP_KERNEL);
655         if (ReservedPagePacket == NULL) {
656                 DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __func__);
657                 return;
658         }
659
660         pHalData = GET_HAL_DATA(padapter);
661         pxmitpriv = &padapter->xmitpriv;
662         pmlmeext = &padapter->mlmeextpriv;
663         pmlmeinfo = &pmlmeext->mlmext_info;
664
665         TxDescLen = TXDESC_SIZE;
666         PageNum = 0;
667
668         /* 3 (1) beacon */
669         BufIndex = TXDESC_OFFSET;
670         /*  skip Beacon Packet */
671         PageNeed = 3;
672
673         PageNum += PageNeed;
674         pHalData->FwRsvdPageStartOffset = PageNum;
675
676         BufIndex += PageNeed*128;
677
678         /* 3 (3) null data */
679         RsvdPageLoc.LocNullData = PageNum;
680         ConstructNullFunctionData(
681                 padapter,
682                 &ReservedPagePacket[BufIndex],
683                 &NullDataLength,
684                 fakemac,
685                 false, 0, 0, false);
686         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
687
688         PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
689         PageNum += PageNeed;
690
691         BufIndex += PageNeed*128;
692
693         /* 3 (6) BT Qos null data */
694         RsvdPageLoc.LocBTQosNull = PageNum;
695         ConstructNullFunctionData(
696                 padapter,
697                 &ReservedPagePacket[BufIndex],
698                 &BTQosNullLength,
699                 fakemac,
700                 true, 0, 0, false);
701         rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
702
703         TotalPacketLen = BufIndex + BTQosNullLength;
704
705         pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
706         if (pmgntframe == NULL)
707                 goto exit;
708
709         /*  update attribute */
710         pattrib = &pmgntframe->attrib;
711         update_mgntframe_attrib23a(padapter, pattrib);
712         pattrib->qsel = 0x10;
713         pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
714         memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
715
716         rtl8723au_mgnt_xmit(padapter, pmgntframe);
717
718         DBG_8723A("%s: Set RSVD page location to Fw\n", __func__);
719         FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
720
721 exit:
722         kfree(ReservedPagePacket);
723 }
724
725 void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter *padapter)
726 {
727         struct hal_data_8723a *pHalData;
728         u8 bRecover = false;
729
730         DBG_8723A("+%s\n", __func__);
731
732         pHalData = GET_HAL_DATA(padapter);
733
734         /*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
735         if (pHalData->RegFwHwTxQCtrl & BIT(6))
736                 bRecover = true;
737
738         /*  To tell Hw the packet is not a real beacon frame. */
739         pHalData->RegFwHwTxQCtrl &= ~BIT(6);
740         rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
741                          pHalData->RegFwHwTxQCtrl);
742         SetFwRsvdPagePkt_BTCoex(padapter);
743
744         /*  To make sure that if there exists an adapter which would like to send beacon. */
745         /*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
746         /*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
747         /*  the beacon cannot be sent by HW. */
748         /*  2010.06.23. Added by tynli. */
749         if (bRecover) {
750                 pHalData->RegFwHwTxQCtrl |= BIT(6);
751                 rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
752                                  pHalData->RegFwHwTxQCtrl);
753         }
754 }
755 #endif