1 // SPDX-License-Identifier: GPL-2.0 2 /****************************************************************************** 3 * 4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. 5 * 6 ******************************************************************************/ 7 #define _RTL8723B_CMD_C_ 8 9 #include <drv_types.h> 10 #include <rtw_debug.h> 11 #include <rtl8723b_hal.h> 12 #include "hal_com_h2c.h" 13 14 #define MAX_H2C_BOX_NUMS 4 15 #define MESSAGE_BOX_SIZE 4 16 17 #define RTL8723B_MAX_CMD_LEN 7 18 #define RTL8723B_EX_MESSAGE_BOX_SIZE 4 19 20 static u8 _is_fw_read_cmd_down(struct adapter *padapter, u8 msgbox_num) 21 { 22 u8 read_down = false; 23 int retry_cnts = 100; 24 25 u8 valid; 26 27 do { 28 valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num); 29 if (0 == valid) { 30 read_down = true; 31 } 32 } while ((!read_down) && (retry_cnts--)); 33 34 return read_down; 35 36 } 37 38 39 /***************************************** 40 * H2C Msg format : 41 *| 31 - 8 |7-5 | 4 - 0 | 42 *| h2c_msg |Class |CMD_ID | 43 *| 31-0 | 44 *| Ext msg | 45 * 46 ******************************************/ 47 s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) 48 { 49 u8 h2c_box_num; 50 u32 msgbox_addr; 51 u32 msgbox_ex_addr = 0; 52 struct hal_com_data *pHalData; 53 u32 h2c_cmd = 0; 54 u32 h2c_cmd_ex = 0; 55 s32 ret = _FAIL; 56 57 padapter = GET_PRIMARY_ADAPTER(padapter); 58 pHalData = GET_HAL_DATA(padapter); 59 if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex))) 60 return ret; 61 62 if (!pCmdBuffer) { 63 goto exit; 64 } 65 66 if (CmdLen > RTL8723B_MAX_CMD_LEN) { 67 goto exit; 68 } 69 70 if (padapter->bSurpriseRemoved) 71 goto exit; 72 73 /* pay attention to if race condition happened in H2C cmd setting. */ 74 do { 75 h2c_box_num = pHalData->LastHMEBoxNum; 76 77 if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) 78 goto exit; 79 80 if (CmdLen <= 3) 81 memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen); 82 else { 83 memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3); 84 memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, CmdLen-3); 85 /* *(u8 *)(&h2c_cmd) |= BIT(7); */ 86 } 87 88 *(u8 *)(&h2c_cmd) |= ElementID; 89 90 if (CmdLen > 3) { 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); 93 } 94 msgbox_addr = REG_HMEBOX_0 + (h2c_box_num*MESSAGE_BOX_SIZE); 95 rtw_write32(padapter, msgbox_addr, h2c_cmd); 96 97 pHalData->LastHMEBoxNum = (h2c_box_num+1) % MAX_H2C_BOX_NUMS; 98 99 } while (0); 100 101 ret = _SUCCESS; 102 103 exit: 104 105 mutex_unlock(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex)); 106 return ret; 107 } 108 109 static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength) 110 { 111 struct ieee80211_hdr *pwlanhdr; 112 __le16 *fctrl; 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 118 pwlanhdr = (struct ieee80211_hdr *)pframe; 119 120 fctrl = &(pwlanhdr->frame_control); 121 *(fctrl) = 0; 122 123 eth_broadcast_addr(pwlanhdr->addr1); 124 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 125 memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); 126 127 SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); 128 /* pmlmeext->mgnt_seq++; */ 129 SetFrameSubType(pframe, WIFI_BEACON); 130 131 pframe += sizeof(struct ieee80211_hdr_3addr); 132 pktlen = sizeof(struct ieee80211_hdr_3addr); 133 134 /* timestamp will be inserted by hardware */ 135 pframe += 8; 136 pktlen += 8; 137 138 /* beacon interval: 2 bytes */ 139 memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); 140 141 pframe += 2; 142 pktlen += 2; 143 144 /* capability info: 2 bytes */ 145 memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); 146 147 pframe += 2; 148 pktlen += 2; 149 150 if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { 151 pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fix_ie); 152 memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fix_ie), pktlen); 153 154 goto _ConstructBeacon; 155 } 156 157 /* below for ad-hoc mode */ 158 159 /* SSID */ 160 pframe = rtw_set_ie(pframe, WLAN_EID_SSID, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); 161 162 /* supported rates... */ 163 rate_len = rtw_get_rateset_len(cur_network->SupportedRates); 164 pframe = rtw_set_ie(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); 165 166 /* DS parameter set */ 167 pframe = rtw_set_ie(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); 168 169 if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { 170 u32 ATIMWindow; 171 /* IBSS Parameter Set... */ 172 /* ATIMWindow = cur->Configuration.ATIMWindow; */ 173 ATIMWindow = 0; 174 pframe = rtw_set_ie(pframe, WLAN_EID_IBSS_PARAMS, 2, (unsigned char *)(&ATIMWindow), &pktlen); 175 } 176 177 178 /* todo: ERP IE */ 179 180 181 /* EXTERNDED SUPPORTED RATE */ 182 if (rate_len > 8) 183 pframe = rtw_set_ie(pframe, WLAN_EID_EXT_SUPP_RATES, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); 184 185 186 /* todo:HT for adhoc */ 187 188 _ConstructBeacon: 189 190 if ((pktlen + TXDESC_SIZE) > 512) 191 return; 192 193 *pLength = pktlen; 194 195 } 196 197 static void ConstructPSPoll(struct adapter *padapter, u8 *pframe, u32 *pLength) 198 { 199 struct ieee80211_hdr *pwlanhdr; 200 __le16 *fctrl; 201 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 202 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 203 204 pwlanhdr = (struct ieee80211_hdr *)pframe; 205 206 /* Frame control. */ 207 fctrl = &(pwlanhdr->frame_control); 208 *(fctrl) = 0; 209 SetPwrMgt(fctrl); 210 SetFrameSubType(pframe, WIFI_PSPOLL); 211 212 /* AID. */ 213 SetDuration(pframe, (pmlmeinfo->aid | 0xc000)); 214 215 /* BSSID. */ 216 memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 217 218 /* TA. */ 219 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 220 221 *pLength = 16; 222 } 223 224 static void ConstructNullFunctionData( 225 struct adapter *padapter, 226 u8 *pframe, 227 u32 *pLength, 228 u8 *StaAddr, 229 u8 bQoS, 230 u8 AC, 231 u8 bEosp, 232 u8 bForcePowerSave 233 ) 234 { 235 struct ieee80211_hdr *pwlanhdr; 236 __le16 *fctrl; 237 u32 pktlen; 238 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 239 struct wlan_network *cur_network = &pmlmepriv->cur_network; 240 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 241 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 242 243 pwlanhdr = (struct ieee80211_hdr *)pframe; 244 245 fctrl = &pwlanhdr->frame_control; 246 *(fctrl) = 0; 247 if (bForcePowerSave) 248 SetPwrMgt(fctrl); 249 250 switch (cur_network->network.InfrastructureMode) { 251 case Ndis802_11Infrastructure: 252 SetToDs(fctrl); 253 memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 254 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 255 memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); 256 break; 257 case Ndis802_11APMode: 258 SetFrDs(fctrl); 259 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); 260 memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 261 memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); 262 break; 263 case Ndis802_11IBSS: 264 default: 265 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); 266 memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 267 memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 268 break; 269 } 270 271 SetSeqNum(pwlanhdr, 0); 272 273 if (bQoS) { 274 struct ieee80211_qos_hdr *pwlanqoshdr; 275 276 SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); 277 278 pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe; 279 SetPriority(&pwlanqoshdr->qos_ctrl, AC); 280 SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp); 281 282 pktlen = sizeof(struct ieee80211_qos_hdr); 283 } else { 284 SetFrameSubType(pframe, WIFI_DATA_NULL); 285 286 pktlen = sizeof(struct ieee80211_hdr_3addr); 287 } 288 289 *pLength = pktlen; 290 } 291 292 /* 293 * To check if reserved page content is destroyed by beacon because beacon 294 * is too large. 295 */ 296 /* 2010.06.23. Added by tynli. */ 297 void CheckFwRsvdPageContent(struct adapter *Adapter) 298 { 299 } 300 301 static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) 302 { 303 u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0}; 304 305 SET_8723B_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp); 306 SET_8723B_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); 307 SET_8723B_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); 308 SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); 309 SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull); 310 311 FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); 312 } 313 314 static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) 315 { 316 } 317 318 void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid) 319 { 320 u8 u1H2CMediaStatusRptParm[H2C_MEDIA_STATUS_RPT_LEN] = {0}; 321 u8 macid_end = 0; 322 323 SET_8723B_H2CCMD_MSRRPT_PARM_OPMODE(u1H2CMediaStatusRptParm, mstatus); 324 SET_8723B_H2CCMD_MSRRPT_PARM_MACID_IND(u1H2CMediaStatusRptParm, 0); 325 SET_8723B_H2CCMD_MSRRPT_PARM_MACID(u1H2CMediaStatusRptParm, macid); 326 SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(u1H2CMediaStatusRptParm, macid_end); 327 328 FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm); 329 } 330 331 void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid, u8 bw, u8 sgi, u32 mask) 332 { 333 u8 u1H2CMacIdConfigParm[H2C_MACID_CFG_LEN] = {0}; 334 335 SET_8723B_H2CCMD_MACID_CFG_MACID(u1H2CMacIdConfigParm, mac_id); 336 SET_8723B_H2CCMD_MACID_CFG_RAID(u1H2CMacIdConfigParm, raid); 337 SET_8723B_H2CCMD_MACID_CFG_SGI_EN(u1H2CMacIdConfigParm, sgi ? 1 : 0); 338 SET_8723B_H2CCMD_MACID_CFG_BW(u1H2CMacIdConfigParm, bw); 339 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK0(u1H2CMacIdConfigParm, (u8)(mask & 0x000000ff)); 340 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK1(u1H2CMacIdConfigParm, (u8)((mask & 0x0000ff00) >> 8)); 341 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(u1H2CMacIdConfigParm, (u8)((mask & 0x00ff0000) >> 16)); 342 SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(u1H2CMacIdConfigParm, (u8)((mask & 0xff000000) >> 24)); 343 344 FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm); 345 } 346 347 void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param) 348 { 349 u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN] = {0}; 350 u8 mac_id = *param; 351 u8 rssi = *(param+2); 352 u8 uldl_state = 0; 353 354 SET_8723B_H2CCMD_RSSI_SETTING_MACID(u1H2CRssiSettingParm, mac_id); 355 SET_8723B_H2CCMD_RSSI_SETTING_RSSI(u1H2CRssiSettingParm, rssi); 356 SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(u1H2CRssiSettingParm, uldl_state); 357 358 FillH2CCmd8723B(padapter, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, u1H2CRssiSettingParm); 359 } 360 361 void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode) 362 { 363 int i; 364 struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); 365 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; 366 u8 u1H2CPwrModeParm[H2C_PWRMODE_LEN] = {0}; 367 u8 PowerState = 0, awake_intvl = 1, byte5 = 0, rlbm = 0; 368 369 if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16) 370 awake_intvl = pwrpriv->dtim+1;/* DTIM = (awake_intvl - 1) */ 371 else 372 awake_intvl = 3;/* DTIM =2 */ 373 374 rlbm = 2; 375 376 if (padapter->registrypriv.wifi_spec == 1) { 377 awake_intvl = 2; 378 rlbm = 2; 379 } 380 381 if (psmode > 0) { 382 if (hal_btcoex_IsBtControlLps(padapter) == true) { 383 PowerState = hal_btcoex_RpwmVal(padapter); 384 byte5 = hal_btcoex_LpsVal(padapter); 385 386 if ((rlbm == 2) && (byte5 & BIT(4))) { 387 /* Keep awake interval to 1 to prevent from */ 388 /* decreasing coex performance */ 389 awake_intvl = 2; 390 rlbm = 2; 391 } 392 } else { 393 PowerState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ 394 byte5 = 0x40; 395 } 396 } else { 397 PowerState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ 398 byte5 = 0x40; 399 } 400 401 SET_8723B_H2CCMD_PWRMODE_PARM_MODE(u1H2CPwrModeParm, (psmode > 0) ? 1 : 0); 402 SET_8723B_H2CCMD_PWRMODE_PARM_SMART_PS(u1H2CPwrModeParm, pwrpriv->smart_ps); 403 SET_8723B_H2CCMD_PWRMODE_PARM_RLBM(u1H2CPwrModeParm, rlbm); 404 SET_8723B_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1H2CPwrModeParm, awake_intvl); 405 SET_8723B_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1H2CPwrModeParm, padapter->registrypriv.uapsd_enable); 406 SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(u1H2CPwrModeParm, PowerState); 407 SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(u1H2CPwrModeParm, byte5); 408 if (psmode != PS_MODE_ACTIVE) { 409 if (!pmlmeext->adaptive_tsf_done && pmlmeext->bcn_cnt > 0) { 410 u8 ratio_20_delay, ratio_80_delay; 411 412 /* byte 6 for adaptive_early_32k */ 413 /* 0:3] = DrvBcnEarly (ms) , [4:7] = DrvBcnTimeOut (ms) */ 414 /* 20% for DrvBcnEarly, 80% for DrvBcnTimeOut */ 415 ratio_20_delay = 0; 416 ratio_80_delay = 0; 417 pmlmeext->DrvBcnEarly = 0xff; 418 pmlmeext->DrvBcnTimeOut = 0xff; 419 420 for (i = 0; i < 9; i++) { 421 pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i]*100)/pmlmeext->bcn_cnt; 422 423 ratio_20_delay += pmlmeext->bcn_delay_ratio[i]; 424 ratio_80_delay += pmlmeext->bcn_delay_ratio[i]; 425 426 if (ratio_20_delay > 20 && pmlmeext->DrvBcnEarly == 0xff) 427 pmlmeext->DrvBcnEarly = i; 428 429 if (ratio_80_delay > 80 && pmlmeext->DrvBcnTimeOut == 0xff) 430 pmlmeext->DrvBcnTimeOut = i; 431 432 /* reset adaptive_early_32k cnt */ 433 pmlmeext->bcn_delay_cnt[i] = 0; 434 pmlmeext->bcn_delay_ratio[i] = 0; 435 436 } 437 438 pmlmeext->bcn_cnt = 0; 439 pmlmeext->adaptive_tsf_done = true; 440 441 } 442 443 /* offload to FW if fw version > v15.10 444 pmlmeext->DrvBcnEarly = 0; 445 pmlmeext->DrvBcnTimeOut =7; 446 447 if ((pmlmeext->DrvBcnEarly!= 0Xff) && (pmlmeext->DrvBcnTimeOut!= 0xff)) 448 u1H2CPwrModeParm[H2C_PWRMODE_LEN-1] = BIT(0) | ((pmlmeext->DrvBcnEarly<<1)&0x0E) |((pmlmeext->DrvBcnTimeOut<<4)&0xf0) ; 449 */ 450 451 } 452 453 hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN); 454 455 FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, u1H2CPwrModeParm); 456 } 457 458 void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter) 459 { 460 u8 u1H2CPsTuneParm[H2C_PSTUNEPARAM_LEN] = {0}; 461 u8 bcn_to_limit = 10; /* 10 * 100 * awakeinterval (ms) */ 462 u8 dtim_timeout = 5; /* ms wait broadcast data timer */ 463 u8 ps_timeout = 20; /* ms Keep awake when tx */ 464 u8 dtim_period = 3; 465 466 SET_8723B_H2CCMD_PSTUNE_PARM_BCN_TO_LIMIT(u1H2CPsTuneParm, bcn_to_limit); 467 SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_TIMEOUT(u1H2CPsTuneParm, dtim_timeout); 468 SET_8723B_H2CCMD_PSTUNE_PARM_PS_TIMEOUT(u1H2CPsTuneParm, ps_timeout); 469 SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(u1H2CPsTuneParm, 1); 470 SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(u1H2CPsTuneParm, dtim_period); 471 472 FillH2CCmd8723B(padapter, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm); 473 } 474 475 void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param) 476 { 477 478 FillH2CCmd8723B(padapter, H2C_8723B_FWLPS_IN_IPS_, 1, &cmd_param); 479 } 480 481 /* 482 * Description: Fill the reserved packets that FW will use to RSVD page. 483 * Now we just send 4 types packet to rsvd page. 484 * (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. 485 * 486 * Input: 487 * 488 * bDLFinished - false: At the first time we will send all the packets as 489 * a large packet to Hw, so we need to set the packet length to total length. 490 * 491 * true: At the second time, we should send the first packet (default:beacon) 492 * to Hw again and set the length in descriptor to the real beacon length. 493 */ 494 /* 2009.10.15 by tynli. */ 495 static void rtl8723b_set_FwRsvdPagePkt( 496 struct adapter *padapter, bool bDLFinished 497 ) 498 { 499 struct xmit_frame *pcmdframe; 500 struct pkt_attrib *pattrib; 501 struct xmit_priv *pxmitpriv; 502 struct mlme_ext_priv *pmlmeext; 503 struct mlme_ext_info *pmlmeinfo; 504 struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 505 u32 BeaconLength = 0, PSPollLength = 0; 506 u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0; 507 u8 *ReservedPagePacket; 508 u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; 509 u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; 510 u16 BufIndex, PageSize = 128; 511 u32 TotalPacketLen, MaxRsvdPageBufSize = 0; 512 513 struct rsvdpage_loc RsvdPageLoc; 514 515 pxmitpriv = &padapter->xmitpriv; 516 pmlmeext = &padapter->mlmeextpriv; 517 pmlmeinfo = &pmlmeext->mlmext_info; 518 519 RsvdPageNum = BCNQ_PAGE_NUM_8723B + WOWLAN_PAGE_NUM_8723B; 520 MaxRsvdPageBufSize = RsvdPageNum*PageSize; 521 522 pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); 523 if (!pcmdframe) 524 return; 525 526 ReservedPagePacket = pcmdframe->buf_addr; 527 memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc)); 528 529 /* 3 (1) beacon */ 530 BufIndex = TxDescOffset; 531 ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); 532 533 /* When we count the first page size, we need to reserve description size for the RSVD */ 534 /* packet, it will be filled in front of the packet in TXPKTBUF. */ 535 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); 536 /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ 537 if (CurtPktPageNum == 1) 538 CurtPktPageNum += 1; 539 540 TotalPageNum += CurtPktPageNum; 541 542 BufIndex += (CurtPktPageNum*PageSize); 543 544 /* 3 (2) ps-poll */ 545 RsvdPageLoc.LocPsPoll = TotalPageNum; 546 ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength); 547 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false, false); 548 549 CurtPktPageNum = (u8)PageNum_128(TxDescLen + PSPollLength); 550 551 TotalPageNum += CurtPktPageNum; 552 553 BufIndex += (CurtPktPageNum*PageSize); 554 555 /* 3 (3) null data */ 556 RsvdPageLoc.LocNullData = TotalPageNum; 557 ConstructNullFunctionData( 558 padapter, 559 &ReservedPagePacket[BufIndex], 560 &NullDataLength, 561 get_my_bssid(&pmlmeinfo->network), 562 false, 0, 0, false 563 ); 564 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false, false); 565 566 CurtPktPageNum = (u8)PageNum_128(TxDescLen + NullDataLength); 567 568 TotalPageNum += CurtPktPageNum; 569 570 BufIndex += (CurtPktPageNum*PageSize); 571 572 /* 3 (5) Qos null data */ 573 RsvdPageLoc.LocQosNull = TotalPageNum; 574 ConstructNullFunctionData( 575 padapter, 576 &ReservedPagePacket[BufIndex], 577 &QosNullLength, 578 get_my_bssid(&pmlmeinfo->network), 579 true, 0, 0, false 580 ); 581 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false, false); 582 583 CurtPktPageNum = (u8)PageNum_128(TxDescLen + QosNullLength); 584 585 TotalPageNum += CurtPktPageNum; 586 587 BufIndex += (CurtPktPageNum*PageSize); 588 589 /* 3 (6) BT Qos null data */ 590 RsvdPageLoc.LocBTQosNull = TotalPageNum; 591 ConstructNullFunctionData( 592 padapter, 593 &ReservedPagePacket[BufIndex], 594 &BTQosNullLength, 595 get_my_bssid(&pmlmeinfo->network), 596 true, 0, 0, false 597 ); 598 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false); 599 600 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength); 601 602 TotalPageNum += CurtPktPageNum; 603 604 BufIndex += (CurtPktPageNum*PageSize); 605 606 TotalPacketLen = BufIndex + BTQosNullLength; 607 608 if (TotalPacketLen > MaxRsvdPageBufSize) { 609 goto error; 610 } else { 611 /* update attribute */ 612 pattrib = &pcmdframe->attrib; 613 update_mgntframe_attrib(padapter, pattrib); 614 pattrib->qsel = 0x10; 615 pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; 616 dump_mgntframe_and_wait(padapter, pcmdframe, 100); 617 } 618 619 if (check_fwstate(pmlmepriv, _FW_LINKED)) { 620 rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); 621 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); 622 } else { 623 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); 624 } 625 return; 626 627 error: 628 629 rtw_free_xmitframe(pxmitpriv, pcmdframe); 630 } 631 632 void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) 633 { 634 struct hal_com_data *pHalData = GET_HAL_DATA(padapter); 635 struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 636 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 637 bool bcn_valid = false; 638 u8 DLBcnCount = 0; 639 u32 poll = 0; 640 u8 val8; 641 642 if (mstatus == RT_MEDIA_CONNECT) { 643 bool bRecover = false; 644 u8 v8; 645 646 /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ 647 /* Suggested by filen. Added by tynli. */ 648 rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); 649 650 /* set REG_CR bit 8 */ 651 v8 = rtw_read8(padapter, REG_CR+1); 652 v8 |= BIT(0); /* ENSWBCN */ 653 rtw_write8(padapter, REG_CR+1, v8); 654 655 /* Disable Hw protection for a time which revserd for Hw sending beacon. */ 656 /* Fix download reserved page packet fail that access collision with the protection time. */ 657 /* 2010.05.11. Added by tynli. */ 658 val8 = rtw_read8(padapter, REG_BCN_CTRL); 659 val8 &= ~EN_BCN_FUNCTION; 660 val8 |= DIS_TSF_UDT; 661 rtw_write8(padapter, REG_BCN_CTRL, val8); 662 663 /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ 664 if (pHalData->RegFwHwTxQCtrl & BIT(6)) 665 bRecover = true; 666 667 /* To tell Hw the packet is not a real beacon frame. */ 668 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6)); 669 pHalData->RegFwHwTxQCtrl &= ~BIT(6); 670 671 /* Clear beacon valid check bit. */ 672 rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); 673 rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); 674 675 DLBcnCount = 0; 676 poll = 0; 677 do { 678 /* download rsvd page. */ 679 rtl8723b_set_FwRsvdPagePkt(padapter, 0); 680 DLBcnCount++; 681 do { 682 yield(); 683 /* mdelay(10); */ 684 /* check rsvd page download OK. */ 685 rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid)); 686 poll++; 687 } while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 688 689 } while (!bcn_valid && DLBcnCount <= 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 690 691 if (padapter->bSurpriseRemoved || padapter->bDriverStopped) { 692 } else { 693 struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); 694 pwrctl->fw_psmode_iface_id = padapter->iface_id; 695 } 696 697 /* 2010.05.11. Added by tynli. */ 698 val8 = rtw_read8(padapter, REG_BCN_CTRL); 699 val8 |= EN_BCN_FUNCTION; 700 val8 &= ~DIS_TSF_UDT; 701 rtw_write8(padapter, REG_BCN_CTRL, val8); 702 703 /* To make sure that if there exists an adapter which would like to send beacon. */ 704 /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ 705 /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ 706 /* the beacon cannot be sent by HW. */ 707 /* 2010.06.23. Added by tynli. */ 708 if (bRecover) { 709 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6)); 710 pHalData->RegFwHwTxQCtrl |= BIT(6); 711 } 712 713 /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ 714 v8 = rtw_read8(padapter, REG_CR+1); 715 v8 &= ~BIT(0); /* ~ENSWBCN */ 716 rtw_write8(padapter, REG_CR+1, v8); 717 } 718 } 719 720 void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus) 721 { 722 if (mstatus == 1) 723 rtl8723b_download_rsvd_page(padapter, RT_MEDIA_CONNECT); 724 } 725 726 /* arg[0] = macid */ 727 /* arg[1] = raid */ 728 /* arg[2] = shortGIrate */ 729 /* arg[3] = init_rate */ 730 void rtl8723b_Add_RateATid( 731 struct adapter *padapter, 732 u32 bitmap, 733 u8 *arg, 734 u8 rssi_level 735 ) 736 { 737 struct hal_com_data *pHalData = GET_HAL_DATA(padapter); 738 struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; 739 struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 740 struct sta_info *psta; 741 u8 mac_id = arg[0]; 742 u8 raid = arg[1]; 743 u8 shortGI = arg[2]; 744 u8 bw; 745 u32 mask = bitmap&0x0FFFFFFF; 746 747 psta = pmlmeinfo->FW_sta_info[mac_id].psta; 748 if (!psta) 749 return; 750 751 bw = psta->bw_mode; 752 753 if (rssi_level != DM_RATR_STA_INIT) 754 mask = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level); 755 756 rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid, bw, shortGI, mask); 757 } 758 759 static void ConstructBtNullFunctionData( 760 struct adapter *padapter, 761 u8 *pframe, 762 u32 *pLength, 763 u8 *StaAddr, 764 u8 bQoS, 765 u8 AC, 766 u8 bEosp, 767 u8 bForcePowerSave 768 ) 769 { 770 struct ieee80211_hdr *pwlanhdr; 771 __le16 *fctrl; 772 u32 pktlen; 773 u8 bssid[ETH_ALEN]; 774 775 pwlanhdr = (struct ieee80211_hdr *)pframe; 776 777 if (!StaAddr) { 778 memcpy(bssid, myid(&padapter->eeprompriv), ETH_ALEN); 779 StaAddr = bssid; 780 } 781 782 fctrl = &pwlanhdr->frame_control; 783 *fctrl = 0; 784 if (bForcePowerSave) 785 SetPwrMgt(fctrl); 786 787 SetFrDs(fctrl); 788 memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); 789 memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); 790 memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); 791 792 SetDuration(pwlanhdr, 0); 793 SetSeqNum(pwlanhdr, 0); 794 795 if (bQoS) { 796 struct ieee80211_qos_hdr *pwlanqoshdr; 797 798 SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); 799 800 pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe; 801 SetPriority(&pwlanqoshdr->qos_ctrl, AC); 802 SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp); 803 804 pktlen = sizeof(struct ieee80211_qos_hdr); 805 } else { 806 SetFrameSubType(pframe, WIFI_DATA_NULL); 807 808 pktlen = sizeof(struct ieee80211_hdr_3addr); 809 } 810 811 *pLength = pktlen; 812 } 813 814 static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) 815 { 816 struct xmit_frame *pcmdframe; 817 struct pkt_attrib *pattrib; 818 struct xmit_priv *pxmitpriv; 819 u32 BeaconLength = 0; 820 u32 BTQosNullLength = 0; 821 u8 *ReservedPagePacket; 822 u8 TxDescLen, TxDescOffset; 823 u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; 824 u16 BufIndex, PageSize; 825 u32 TotalPacketLen, MaxRsvdPageBufSize = 0; 826 struct rsvdpage_loc RsvdPageLoc; 827 828 pxmitpriv = &padapter->xmitpriv; 829 TxDescLen = TXDESC_SIZE; 830 TxDescOffset = TXDESC_OFFSET; 831 PageSize = PAGE_SIZE_TX_8723B; 832 833 RsvdPageNum = BCNQ_PAGE_NUM_8723B; 834 MaxRsvdPageBufSize = RsvdPageNum*PageSize; 835 836 pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); 837 if (!pcmdframe) 838 return; 839 840 ReservedPagePacket = pcmdframe->buf_addr; 841 memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc)); 842 843 /* 3 (1) beacon */ 844 BufIndex = TxDescOffset; 845 ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); 846 847 /* When we count the first page size, we need to reserve description size for the RSVD */ 848 /* packet, it will be filled in front of the packet in TXPKTBUF. */ 849 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); 850 /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ 851 if (CurtPktPageNum == 1) 852 CurtPktPageNum += 1; 853 TotalPageNum += CurtPktPageNum; 854 855 BufIndex += (CurtPktPageNum*PageSize); 856 857 /* Jump to lastest page */ 858 if (BufIndex < (MaxRsvdPageBufSize - PageSize)) { 859 BufIndex = TxDescOffset + (MaxRsvdPageBufSize - PageSize); 860 TotalPageNum = BCNQ_PAGE_NUM_8723B - 1; 861 } 862 863 /* 3 (6) BT Qos null data */ 864 RsvdPageLoc.LocBTQosNull = TotalPageNum; 865 ConstructBtNullFunctionData( 866 padapter, 867 &ReservedPagePacket[BufIndex], 868 &BTQosNullLength, 869 NULL, 870 true, 0, 0, false 871 ); 872 rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false); 873 874 CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength); 875 876 TotalPageNum += CurtPktPageNum; 877 878 TotalPacketLen = BufIndex + BTQosNullLength; 879 if (TotalPacketLen > MaxRsvdPageBufSize) 880 goto error; 881 882 /* update attribute */ 883 pattrib = &pcmdframe->attrib; 884 update_mgntframe_attrib(padapter, pattrib); 885 pattrib->qsel = 0x10; 886 pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; 887 dump_mgntframe_and_wait(padapter, pcmdframe, 100); 888 889 rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); 890 rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); 891 892 return; 893 894 error: 895 rtw_free_xmitframe(pxmitpriv, pcmdframe); 896 } 897 898 void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter) 899 { 900 struct hal_com_data *pHalData; 901 struct mlme_ext_priv *pmlmeext; 902 struct mlme_ext_info *pmlmeinfo; 903 u8 bRecover = false; 904 u8 bcn_valid = false; 905 u8 DLBcnCount = 0; 906 u32 poll = 0; 907 u8 val8; 908 909 pHalData = GET_HAL_DATA(padapter); 910 pmlmeext = &padapter->mlmeextpriv; 911 pmlmeinfo = &pmlmeext->mlmext_info; 912 913 /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ 914 /* Suggested by filen. Added by tynli. */ 915 rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); 916 917 /* set REG_CR bit 8 */ 918 val8 = rtw_read8(padapter, REG_CR+1); 919 val8 |= BIT(0); /* ENSWBCN */ 920 rtw_write8(padapter, REG_CR+1, val8); 921 922 /* Disable Hw protection for a time which revserd for Hw sending beacon. */ 923 /* Fix download reserved page packet fail that access collision with the protection time. */ 924 /* 2010.05.11. Added by tynli. */ 925 val8 = rtw_read8(padapter, REG_BCN_CTRL); 926 val8 &= ~EN_BCN_FUNCTION; 927 val8 |= DIS_TSF_UDT; 928 rtw_write8(padapter, REG_BCN_CTRL, val8); 929 930 /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ 931 if (pHalData->RegFwHwTxQCtrl & BIT(6)) 932 bRecover = true; 933 934 /* To tell Hw the packet is not a real beacon frame. */ 935 pHalData->RegFwHwTxQCtrl &= ~BIT(6); 936 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); 937 938 /* Clear beacon valid check bit. */ 939 rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); 940 rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); 941 942 DLBcnCount = 0; 943 poll = 0; 944 do { 945 SetFwRsvdPagePkt_BTCoex(padapter); 946 DLBcnCount++; 947 do { 948 yield(); 949 /* mdelay(10); */ 950 /* check rsvd page download OK. */ 951 rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, &bcn_valid); 952 poll++; 953 } while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 954 } while (!bcn_valid && (DLBcnCount <= 100) && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 955 956 if (bcn_valid) { 957 struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); 958 pwrctl->fw_psmode_iface_id = padapter->iface_id; 959 } 960 961 /* 2010.05.11. Added by tynli. */ 962 val8 = rtw_read8(padapter, REG_BCN_CTRL); 963 val8 |= EN_BCN_FUNCTION; 964 val8 &= ~DIS_TSF_UDT; 965 rtw_write8(padapter, REG_BCN_CTRL, val8); 966 967 /* To make sure that if there exists an adapter which would like to send beacon. */ 968 /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ 969 /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ 970 /* the beacon cannot be sent by HW. */ 971 /* 2010.06.23. Added by tynli. */ 972 if (bRecover) { 973 pHalData->RegFwHwTxQCtrl |= BIT(6); 974 rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); 975 } 976 977 /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ 978 val8 = rtw_read8(padapter, REG_CR+1); 979 val8 &= ~BIT(0); /* ~ENSWBCN */ 980 rtw_write8(padapter, REG_CR+1, val8); 981 } 982