1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
6 ******************************************************************************/
7 #define _RTL8723B_CMD_C_
10 #include <rtw_debug.h>
11 #include <rtl8723b_hal.h>
12 #include "hal_com_h2c.h"
14 #define MAX_H2C_BOX_NUMS 4
15 #define MESSAGE_BOX_SIZE 4
17 #define RTL8723B_MAX_CMD_LEN 7
18 #define RTL8723B_EX_MESSAGE_BOX_SIZE 4
20 static u8 _is_fw_read_cmd_down(struct adapter *padapter, u8 msgbox_num)
28 valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num);
32 } while ((!read_down) && (retry_cnts--));
39 /*****************************************
41 *| 31 - 8 |7-5 | 4 - 0 |
42 *| h2c_msg |Class |CMD_ID |
46 ******************************************/
47 s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
51 u32 msgbox_ex_addr = 0;
52 struct hal_com_data *pHalData;
57 padapter = GET_PRIMARY_ADAPTER(padapter);
58 pHalData = GET_HAL_DATA(padapter);
59 if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex)))
66 if (CmdLen > RTL8723B_MAX_CMD_LEN) {
70 if (padapter->bSurpriseRemoved)
73 /* pay attention to if race condition happened in H2C cmd setting. */
75 h2c_box_num = pHalData->LastHMEBoxNum;
77 if (!_is_fw_read_cmd_down(padapter, h2c_box_num))
81 memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
83 memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3);
84 memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, CmdLen-3);
85 /* *(u8 *)(&h2c_cmd) |= BIT(7); */
88 *(u8 *)(&h2c_cmd) |= ElementID;
91 msgbox_ex_addr = REG_HMEBOX_EXT0_8723B + (h2c_box_num*RTL8723B_EX_MESSAGE_BOX_SIZE);
92 rtw_write32(padapter, msgbox_ex_addr, h2c_cmd_ex);
94 msgbox_addr = REG_HMEBOX_0 + (h2c_box_num*MESSAGE_BOX_SIZE);
95 rtw_write32(padapter, msgbox_addr, h2c_cmd);
97 pHalData->LastHMEBoxNum = (h2c_box_num+1) % MAX_H2C_BOX_NUMS;
105 mutex_unlock(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex));
109 static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength)
111 struct ieee80211_hdr *pwlanhdr;
113 u32 rate_len, pktlen;
114 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
115 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
116 struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
117 u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
119 pwlanhdr = (struct ieee80211_hdr *)pframe;
121 fctrl = &(pwlanhdr->frame_control);
124 memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
125 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
126 memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
128 SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
129 /* pmlmeext->mgnt_seq++; */
130 SetFrameSubType(pframe, WIFI_BEACON);
132 pframe += sizeof(struct ieee80211_hdr_3addr);
133 pktlen = sizeof(struct ieee80211_hdr_3addr);
135 /* timestamp will be inserted by hardware */
139 /* beacon interval: 2 bytes */
140 memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
145 /* capability info: 2 bytes */
146 memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
151 if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
152 pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fix_ie);
153 memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fix_ie), pktlen);
155 goto _ConstructBeacon;
158 /* below for ad-hoc mode */
161 pframe = rtw_set_ie(pframe, WLAN_EID_SSID, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen);
163 /* supported rates... */
164 rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
165 pframe = rtw_set_ie(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen);
167 /* DS parameter set */
168 pframe = rtw_set_ie(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen);
170 if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
172 /* IBSS Parameter Set... */
173 /* ATIMWindow = cur->Configuration.ATIMWindow; */
175 pframe = rtw_set_ie(pframe, WLAN_EID_IBSS_PARAMS, 2, (unsigned char *)(&ATIMWindow), &pktlen);
182 /* EXTERNDED SUPPORTED RATE */
184 pframe = rtw_set_ie(pframe, WLAN_EID_EXT_SUPP_RATES, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen);
187 /* todo:HT for adhoc */
191 if ((pktlen + TXDESC_SIZE) > 512)
198 static void ConstructPSPoll(struct adapter *padapter, u8 *pframe, u32 *pLength)
200 struct ieee80211_hdr *pwlanhdr;
202 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
203 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
205 pwlanhdr = (struct ieee80211_hdr *)pframe;
208 fctrl = &(pwlanhdr->frame_control);
211 SetFrameSubType(pframe, WIFI_PSPOLL);
214 SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
217 memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
220 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
225 static void ConstructNullFunctionData(
226 struct adapter *padapter,
236 struct ieee80211_hdr *pwlanhdr;
239 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
240 struct wlan_network *cur_network = &pmlmepriv->cur_network;
241 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
242 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
244 pwlanhdr = (struct ieee80211_hdr *)pframe;
246 fctrl = &pwlanhdr->frame_control;
251 switch (cur_network->network.InfrastructureMode) {
252 case Ndis802_11Infrastructure:
254 memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
255 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
256 memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
258 case Ndis802_11APMode:
260 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
261 memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
262 memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
266 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
267 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
268 memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
272 SetSeqNum(pwlanhdr, 0);
275 struct ieee80211_qos_hdr *pwlanqoshdr;
277 SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
279 pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe;
280 SetPriority(&pwlanqoshdr->qos_ctrl, AC);
281 SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp);
283 pktlen = sizeof(struct ieee80211_qos_hdr);
285 SetFrameSubType(pframe, WIFI_DATA_NULL);
287 pktlen = sizeof(struct ieee80211_hdr_3addr);
294 * To check if reserved page content is destroyed by beacon because beacon
297 /* 2010.06.23. Added by tynli. */
298 void CheckFwRsvdPageContent(struct adapter *Adapter)
302 static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc)
304 u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0};
306 SET_8723B_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp);
307 SET_8723B_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll);
308 SET_8723B_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData);
309 SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull);
310 SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull);
312 print_hex_dump_debug(DRIVER_PREFIX ": u1H2CRsvdPageParm:", DUMP_PREFIX_NONE,
313 16, 1, u1H2CRsvdPageParm, H2C_RSVDPAGE_LOC_LEN, false);
315 FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm);
318 static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc)
322 void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid)
324 u8 u1H2CMediaStatusRptParm[H2C_MEDIA_STATUS_RPT_LEN] = {0};
327 SET_8723B_H2CCMD_MSRRPT_PARM_OPMODE(u1H2CMediaStatusRptParm, mstatus);
328 SET_8723B_H2CCMD_MSRRPT_PARM_MACID_IND(u1H2CMediaStatusRptParm, 0);
329 SET_8723B_H2CCMD_MSRRPT_PARM_MACID(u1H2CMediaStatusRptParm, macid);
330 SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(u1H2CMediaStatusRptParm, macid_end);
332 print_hex_dump_debug(DRIVER_PREFIX ": u1H2CMediaStatusRptParm:", DUMP_PREFIX_NONE,
333 16, 1, u1H2CMediaStatusRptParm, H2C_MEDIA_STATUS_RPT_LEN, false);
335 FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm);
338 void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid, u8 bw, u8 sgi, u32 mask)
340 u8 u1H2CMacIdConfigParm[H2C_MACID_CFG_LEN] = {0};
342 SET_8723B_H2CCMD_MACID_CFG_MACID(u1H2CMacIdConfigParm, mac_id);
343 SET_8723B_H2CCMD_MACID_CFG_RAID(u1H2CMacIdConfigParm, raid);
344 SET_8723B_H2CCMD_MACID_CFG_SGI_EN(u1H2CMacIdConfigParm, sgi ? 1 : 0);
345 SET_8723B_H2CCMD_MACID_CFG_BW(u1H2CMacIdConfigParm, bw);
346 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK0(u1H2CMacIdConfigParm, (u8)(mask & 0x000000ff));
347 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK1(u1H2CMacIdConfigParm, (u8)((mask & 0x0000ff00) >> 8));
348 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(u1H2CMacIdConfigParm, (u8)((mask & 0x00ff0000) >> 16));
349 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(u1H2CMacIdConfigParm, (u8)((mask & 0xff000000) >> 24));
351 print_hex_dump_debug(DRIVER_PREFIX ": u1H2CMacIdConfigParm:", DUMP_PREFIX_NONE,
352 16, 1, u1H2CMacIdConfigParm, H2C_MACID_CFG_LEN, false);
354 FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm);
357 void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
359 u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN] = {0};
361 u8 rssi = *(param+2);
364 SET_8723B_H2CCMD_RSSI_SETTING_MACID(u1H2CRssiSettingParm, mac_id);
365 SET_8723B_H2CCMD_RSSI_SETTING_RSSI(u1H2CRssiSettingParm, rssi);
366 SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(u1H2CRssiSettingParm, uldl_state);
368 print_hex_dump_debug(DRIVER_PREFIX ": u1H2CRssiSettingParm:", DUMP_PREFIX_NONE,
369 16, 1, u1H2CRssiSettingParm, H2C_RSSI_SETTING_LEN, false);
371 FillH2CCmd8723B(padapter, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, u1H2CRssiSettingParm);
374 void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
377 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
378 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
379 u8 u1H2CPwrModeParm[H2C_PWRMODE_LEN] = {0};
380 u8 PowerState = 0, awake_intvl = 1, byte5 = 0, rlbm = 0;
382 if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16)
383 awake_intvl = pwrpriv->dtim+1;/* DTIM = (awake_intvl - 1) */
385 awake_intvl = 3;/* DTIM =2 */
389 if (padapter->registrypriv.wifi_spec == 1) {
395 if (hal_btcoex_IsBtControlLps(padapter) == true) {
396 PowerState = hal_btcoex_RpwmVal(padapter);
397 byte5 = hal_btcoex_LpsVal(padapter);
399 if ((rlbm == 2) && (byte5 & BIT(4))) {
400 /* Keep awake interval to 1 to prevent from */
401 /* decreasing coex performance */
406 PowerState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
410 PowerState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
414 SET_8723B_H2CCMD_PWRMODE_PARM_MODE(u1H2CPwrModeParm, (psmode > 0) ? 1 : 0);
415 SET_8723B_H2CCMD_PWRMODE_PARM_SMART_PS(u1H2CPwrModeParm, pwrpriv->smart_ps);
416 SET_8723B_H2CCMD_PWRMODE_PARM_RLBM(u1H2CPwrModeParm, rlbm);
417 SET_8723B_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1H2CPwrModeParm, awake_intvl);
418 SET_8723B_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1H2CPwrModeParm, padapter->registrypriv.uapsd_enable);
419 SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(u1H2CPwrModeParm, PowerState);
420 SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(u1H2CPwrModeParm, byte5);
421 if (psmode != PS_MODE_ACTIVE) {
422 if (!pmlmeext->adaptive_tsf_done && pmlmeext->bcn_cnt > 0) {
423 u8 ratio_20_delay, ratio_80_delay;
425 /* byte 6 for adaptive_early_32k */
426 /* 0:3] = DrvBcnEarly (ms) , [4:7] = DrvBcnTimeOut (ms) */
427 /* 20% for DrvBcnEarly, 80% for DrvBcnTimeOut */
430 pmlmeext->DrvBcnEarly = 0xff;
431 pmlmeext->DrvBcnTimeOut = 0xff;
433 for (i = 0; i < 9; i++) {
434 pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i]*100)/pmlmeext->bcn_cnt;
436 ratio_20_delay += pmlmeext->bcn_delay_ratio[i];
437 ratio_80_delay += pmlmeext->bcn_delay_ratio[i];
439 if (ratio_20_delay > 20 && pmlmeext->DrvBcnEarly == 0xff)
440 pmlmeext->DrvBcnEarly = i;
442 if (ratio_80_delay > 80 && pmlmeext->DrvBcnTimeOut == 0xff)
443 pmlmeext->DrvBcnTimeOut = i;
445 /* reset adaptive_early_32k cnt */
446 pmlmeext->bcn_delay_cnt[i] = 0;
447 pmlmeext->bcn_delay_ratio[i] = 0;
451 pmlmeext->bcn_cnt = 0;
452 pmlmeext->adaptive_tsf_done = true;
456 /* offload to FW if fw version > v15.10
457 pmlmeext->DrvBcnEarly = 0;
458 pmlmeext->DrvBcnTimeOut =7;
460 if ((pmlmeext->DrvBcnEarly!= 0Xff) && (pmlmeext->DrvBcnTimeOut!= 0xff))
461 u1H2CPwrModeParm[H2C_PWRMODE_LEN-1] = BIT(0) | ((pmlmeext->DrvBcnEarly<<1)&0x0E) |((pmlmeext->DrvBcnTimeOut<<4)&0xf0) ;
466 hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
468 print_hex_dump_debug(DRIVER_PREFIX ": u1H2CPwrModeParm:", DUMP_PREFIX_NONE,
469 16, 1, u1H2CPwrModeParm, H2C_PWRMODE_LEN, false);
471 FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, u1H2CPwrModeParm);
474 void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter)
476 u8 u1H2CPsTuneParm[H2C_PSTUNEPARAM_LEN] = {0};
477 u8 bcn_to_limit = 10; /* 10 * 100 * awakeinterval (ms) */
478 u8 dtim_timeout = 5; /* ms wait broadcast data timer */
479 u8 ps_timeout = 20; /* ms Keep awake when tx */
482 SET_8723B_H2CCMD_PSTUNE_PARM_BCN_TO_LIMIT(u1H2CPsTuneParm, bcn_to_limit);
483 SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_TIMEOUT(u1H2CPsTuneParm, dtim_timeout);
484 SET_8723B_H2CCMD_PSTUNE_PARM_PS_TIMEOUT(u1H2CPsTuneParm, ps_timeout);
485 SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(u1H2CPsTuneParm, 1);
486 SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(u1H2CPsTuneParm, dtim_period);
488 print_hex_dump_debug(DRIVER_PREFIX ": u1H2CPsTuneParm:", DUMP_PREFIX_NONE,
489 16, 1, u1H2CPsTuneParm, H2C_PSTUNEPARAM_LEN, false);
491 FillH2CCmd8723B(padapter, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm);
494 void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param)
497 FillH2CCmd8723B(padapter, H2C_8723B_FWLPS_IN_IPS_, 1, &cmd_param);
501 * Description: Fill the reserved packets that FW will use to RSVD page.
502 * Now we just send 4 types packet to rsvd page.
503 * (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp.
507 * bDLFinished - false: At the first time we will send all the packets as
508 * a large packet to Hw, so we need to set the packet length to total length.
510 * true: At the second time, we should send the first packet (default:beacon)
511 * to Hw again and set the length in descriptor to the real beacon length.
513 /* 2009.10.15 by tynli. */
514 static void rtl8723b_set_FwRsvdPagePkt(
515 struct adapter *padapter, bool bDLFinished
518 struct xmit_frame *pcmdframe;
519 struct pkt_attrib *pattrib;
520 struct xmit_priv *pxmitpriv;
521 struct mlme_ext_priv *pmlmeext;
522 struct mlme_ext_info *pmlmeinfo;
523 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
524 u32 BeaconLength = 0, PSPollLength = 0;
525 u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0;
526 u8 *ReservedPagePacket;
527 u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET;
528 u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0;
529 u16 BufIndex, PageSize = 128;
530 u32 TotalPacketLen, MaxRsvdPageBufSize = 0;
532 struct rsvdpage_loc RsvdPageLoc;
534 pxmitpriv = &padapter->xmitpriv;
535 pmlmeext = &padapter->mlmeextpriv;
536 pmlmeinfo = &pmlmeext->mlmext_info;
538 RsvdPageNum = BCNQ_PAGE_NUM_8723B + WOWLAN_PAGE_NUM_8723B;
539 MaxRsvdPageBufSize = RsvdPageNum*PageSize;
541 pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
545 ReservedPagePacket = pcmdframe->buf_addr;
546 memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc));
549 BufIndex = TxDescOffset;
550 ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
552 /* When we count the first page size, we need to reserve description size for the RSVD */
553 /* packet, it will be filled in front of the packet in TXPKTBUF. */
554 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength);
555 /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */
556 if (CurtPktPageNum == 1)
559 TotalPageNum += CurtPktPageNum;
561 BufIndex += (CurtPktPageNum*PageSize);
564 RsvdPageLoc.LocPsPoll = TotalPageNum;
565 ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength);
566 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false, false);
568 CurtPktPageNum = (u8)PageNum_128(TxDescLen + PSPollLength);
570 TotalPageNum += CurtPktPageNum;
572 BufIndex += (CurtPktPageNum*PageSize);
574 /* 3 (3) null data */
575 RsvdPageLoc.LocNullData = TotalPageNum;
576 ConstructNullFunctionData(
578 &ReservedPagePacket[BufIndex],
580 get_my_bssid(&pmlmeinfo->network),
583 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false, false);
585 CurtPktPageNum = (u8)PageNum_128(TxDescLen + NullDataLength);
587 TotalPageNum += CurtPktPageNum;
589 BufIndex += (CurtPktPageNum*PageSize);
591 /* 3 (5) Qos null data */
592 RsvdPageLoc.LocQosNull = TotalPageNum;
593 ConstructNullFunctionData(
595 &ReservedPagePacket[BufIndex],
597 get_my_bssid(&pmlmeinfo->network),
600 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false, false);
602 CurtPktPageNum = (u8)PageNum_128(TxDescLen + QosNullLength);
604 TotalPageNum += CurtPktPageNum;
606 BufIndex += (CurtPktPageNum*PageSize);
608 /* 3 (6) BT Qos null data */
609 RsvdPageLoc.LocBTQosNull = TotalPageNum;
610 ConstructNullFunctionData(
612 &ReservedPagePacket[BufIndex],
614 get_my_bssid(&pmlmeinfo->network),
617 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false);
619 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength);
621 TotalPageNum += CurtPktPageNum;
623 BufIndex += (CurtPktPageNum*PageSize);
625 TotalPacketLen = BufIndex + BTQosNullLength;
627 if (TotalPacketLen > MaxRsvdPageBufSize) {
630 /* update attribute */
631 pattrib = &pcmdframe->attrib;
632 update_mgntframe_attrib(padapter, pattrib);
633 pattrib->qsel = 0x10;
634 pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset;
635 dump_mgntframe_and_wait(padapter, pcmdframe, 100);
638 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
639 rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc);
640 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc);
642 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc);
648 rtw_free_xmitframe(pxmitpriv, pcmdframe);
651 void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus)
653 struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
654 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
655 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
656 bool bcn_valid = false;
661 if (mstatus == RT_MEDIA_CONNECT) {
662 bool bRecover = false;
665 /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
666 /* Suggested by filen. Added by tynli. */
667 rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
669 /* set REG_CR bit 8 */
670 v8 = rtw_read8(padapter, REG_CR+1);
671 v8 |= BIT(0); /* ENSWBCN */
672 rtw_write8(padapter, REG_CR+1, v8);
674 /* Disable Hw protection for a time which revserd for Hw sending beacon. */
675 /* Fix download reserved page packet fail that access collision with the protection time. */
676 /* 2010.05.11. Added by tynli. */
677 val8 = rtw_read8(padapter, REG_BCN_CTRL);
678 val8 &= ~EN_BCN_FUNCTION;
680 rtw_write8(padapter, REG_BCN_CTRL, val8);
682 /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
683 if (pHalData->RegFwHwTxQCtrl & BIT(6))
686 /* To tell Hw the packet is not a real beacon frame. */
687 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6));
688 pHalData->RegFwHwTxQCtrl &= ~BIT(6);
690 /* Clear beacon valid check bit. */
691 rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
692 rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
697 /* download rsvd page. */
698 rtl8723b_set_FwRsvdPagePkt(padapter, 0);
703 /* check rsvd page download OK. */
704 rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid));
706 } while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
708 } while (!bcn_valid && DLBcnCount <= 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
710 if (padapter->bSurpriseRemoved || padapter->bDriverStopped) {
712 struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
713 pwrctl->fw_psmode_iface_id = padapter->iface_id;
716 /* 2010.05.11. Added by tynli. */
717 val8 = rtw_read8(padapter, REG_BCN_CTRL);
718 val8 |= EN_BCN_FUNCTION;
719 val8 &= ~DIS_TSF_UDT;
720 rtw_write8(padapter, REG_BCN_CTRL, val8);
722 /* To make sure that if there exists an adapter which would like to send beacon. */
723 /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */
724 /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
725 /* the beacon cannot be sent by HW. */
726 /* 2010.06.23. Added by tynli. */
728 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6));
729 pHalData->RegFwHwTxQCtrl |= BIT(6);
732 /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
733 v8 = rtw_read8(padapter, REG_CR+1);
734 v8 &= ~BIT(0); /* ~ENSWBCN */
735 rtw_write8(padapter, REG_CR+1, v8);
739 void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus)
742 rtl8723b_download_rsvd_page(padapter, RT_MEDIA_CONNECT);
747 /* arg[2] = shortGIrate */
748 /* arg[3] = init_rate */
749 void rtl8723b_Add_RateATid(
750 struct adapter *padapter,
756 struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
757 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
758 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
759 struct sta_info *psta;
764 u32 mask = bitmap&0x0FFFFFFF;
766 psta = pmlmeinfo->FW_sta_info[mac_id].psta;
772 if (rssi_level != DM_RATR_STA_INIT)
773 mask = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level);
775 rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid, bw, shortGI, mask);
778 static void ConstructBtNullFunctionData(
779 struct adapter *padapter,
789 struct ieee80211_hdr *pwlanhdr;
794 pwlanhdr = (struct ieee80211_hdr *)pframe;
797 memcpy(bssid, myid(&padapter->eeprompriv), ETH_ALEN);
801 fctrl = &pwlanhdr->frame_control;
807 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
808 memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
809 memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN);
811 SetDuration(pwlanhdr, 0);
812 SetSeqNum(pwlanhdr, 0);
815 struct ieee80211_qos_hdr *pwlanqoshdr;
817 SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
819 pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe;
820 SetPriority(&pwlanqoshdr->qos_ctrl, AC);
821 SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp);
823 pktlen = sizeof(struct ieee80211_qos_hdr);
825 SetFrameSubType(pframe, WIFI_DATA_NULL);
827 pktlen = sizeof(struct ieee80211_hdr_3addr);
833 static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter)
835 struct xmit_frame *pcmdframe;
836 struct pkt_attrib *pattrib;
837 struct xmit_priv *pxmitpriv;
838 u32 BeaconLength = 0;
839 u32 BTQosNullLength = 0;
840 u8 *ReservedPagePacket;
841 u8 TxDescLen, TxDescOffset;
842 u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0;
843 u16 BufIndex, PageSize;
844 u32 TotalPacketLen, MaxRsvdPageBufSize = 0;
845 struct rsvdpage_loc RsvdPageLoc;
847 pxmitpriv = &padapter->xmitpriv;
848 TxDescLen = TXDESC_SIZE;
849 TxDescOffset = TXDESC_OFFSET;
850 PageSize = PAGE_SIZE_TX_8723B;
852 RsvdPageNum = BCNQ_PAGE_NUM_8723B;
853 MaxRsvdPageBufSize = RsvdPageNum*PageSize;
855 pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv);
859 ReservedPagePacket = pcmdframe->buf_addr;
860 memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc));
863 BufIndex = TxDescOffset;
864 ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
866 /* When we count the first page size, we need to reserve description size for the RSVD */
867 /* packet, it will be filled in front of the packet in TXPKTBUF. */
868 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength);
869 /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */
870 if (CurtPktPageNum == 1)
872 TotalPageNum += CurtPktPageNum;
874 BufIndex += (CurtPktPageNum*PageSize);
876 /* Jump to lastest page */
877 if (BufIndex < (MaxRsvdPageBufSize - PageSize)) {
878 BufIndex = TxDescOffset + (MaxRsvdPageBufSize - PageSize);
879 TotalPageNum = BCNQ_PAGE_NUM_8723B - 1;
882 /* 3 (6) BT Qos null data */
883 RsvdPageLoc.LocBTQosNull = TotalPageNum;
884 ConstructBtNullFunctionData(
886 &ReservedPagePacket[BufIndex],
891 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false);
893 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength);
895 TotalPageNum += CurtPktPageNum;
897 TotalPacketLen = BufIndex + BTQosNullLength;
898 if (TotalPacketLen > MaxRsvdPageBufSize)
901 /* update attribute */
902 pattrib = &pcmdframe->attrib;
903 update_mgntframe_attrib(padapter, pattrib);
904 pattrib->qsel = 0x10;
905 pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset;
906 dump_mgntframe_and_wait(padapter, pcmdframe, 100);
908 rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc);
909 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc);
914 rtw_free_xmitframe(pxmitpriv, pcmdframe);
917 void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter)
919 struct hal_com_data *pHalData;
920 struct mlme_ext_priv *pmlmeext;
921 struct mlme_ext_info *pmlmeinfo;
923 u8 bcn_valid = false;
928 pHalData = GET_HAL_DATA(padapter);
929 pmlmeext = &padapter->mlmeextpriv;
930 pmlmeinfo = &pmlmeext->mlmext_info;
932 /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
933 /* Suggested by filen. Added by tynli. */
934 rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
936 /* set REG_CR bit 8 */
937 val8 = rtw_read8(padapter, REG_CR+1);
938 val8 |= BIT(0); /* ENSWBCN */
939 rtw_write8(padapter, REG_CR+1, val8);
941 /* Disable Hw protection for a time which revserd for Hw sending beacon. */
942 /* Fix download reserved page packet fail that access collision with the protection time. */
943 /* 2010.05.11. Added by tynli. */
944 val8 = rtw_read8(padapter, REG_BCN_CTRL);
945 val8 &= ~EN_BCN_FUNCTION;
947 rtw_write8(padapter, REG_BCN_CTRL, val8);
949 /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
950 if (pHalData->RegFwHwTxQCtrl & BIT(6))
953 /* To tell Hw the packet is not a real beacon frame. */
954 pHalData->RegFwHwTxQCtrl &= ~BIT(6);
955 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
957 /* Clear beacon valid check bit. */
958 rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
959 rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL);
964 SetFwRsvdPagePkt_BTCoex(padapter);
969 /* check rsvd page download OK. */
970 rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, &bcn_valid);
972 } while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
973 } while (!bcn_valid && (DLBcnCount <= 100) && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
976 struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
977 pwrctl->fw_psmode_iface_id = padapter->iface_id;
980 /* 2010.05.11. Added by tynli. */
981 val8 = rtw_read8(padapter, REG_BCN_CTRL);
982 val8 |= EN_BCN_FUNCTION;
983 val8 &= ~DIS_TSF_UDT;
984 rtw_write8(padapter, REG_BCN_CTRL, val8);
986 /* To make sure that if there exists an adapter which would like to send beacon. */
987 /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */
988 /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
989 /* the beacon cannot be sent by HW. */
990 /* 2010.06.23. Added by tynli. */
992 pHalData->RegFwHwTxQCtrl |= BIT(6);
993 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
996 /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
997 val8 = rtw_read8(padapter, REG_CR+1);
998 val8 &= ~BIT(0); /* ~ENSWBCN */
999 rtw_write8(padapter, REG_CR+1, val8);