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