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 29static 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******************************************/ 50int 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 111exit: 112 mutex_unlock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex); 113 return ret; 114} 115 116int 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 127int 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 */ 146void 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 176void 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 204static void 205ConstructBeacon(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 296static 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 322static void 323ConstructNullFunctionData(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 394static 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. */ 449static 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 579exit: 580 kfree(ReservedPagePacket); 581} 582 583void 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 656static 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 741exit: 742 kfree(ReservedPagePacket); 743} 744 745void 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 776