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