158391efdSNathan Chancellor // SPDX-License-Identifier: GPL-2.0 2554c0a3aSHans de Goede /****************************************************************************** 3554c0a3aSHans de Goede * 4554c0a3aSHans de Goede * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. 5554c0a3aSHans de Goede * 6554c0a3aSHans de Goede ******************************************************************************/ 7554c0a3aSHans de Goede #define _RTL8723B_CMD_C_ 8554c0a3aSHans de Goede 9554c0a3aSHans de Goede #include <drv_types.h> 10554c0a3aSHans de Goede #include <rtw_debug.h> 11554c0a3aSHans de Goede #include <rtl8723b_hal.h> 12554c0a3aSHans de Goede #include "hal_com_h2c.h" 13554c0a3aSHans de Goede 14554c0a3aSHans de Goede #define MAX_H2C_BOX_NUMS 4 15554c0a3aSHans de Goede #define MESSAGE_BOX_SIZE 4 16554c0a3aSHans de Goede 17554c0a3aSHans de Goede #define RTL8723B_MAX_CMD_LEN 7 18554c0a3aSHans de Goede #define RTL8723B_EX_MESSAGE_BOX_SIZE 4 19554c0a3aSHans de Goede 20554c0a3aSHans de Goede static u8 _is_fw_read_cmd_down(struct adapter *padapter, u8 msgbox_num) 21554c0a3aSHans de Goede { 22554c0a3aSHans de Goede u8 read_down = false; 23554c0a3aSHans de Goede int retry_cnts = 100; 24554c0a3aSHans de Goede 25554c0a3aSHans de Goede u8 valid; 26554c0a3aSHans de Goede 27554c0a3aSHans de Goede /* DBG_8192C(" _is_fw_read_cmd_down , reg_1cc(%x), msg_box(%d)...\n", rtw_read8(padapter, REG_HMETFR), msgbox_num); */ 28554c0a3aSHans de Goede 29554c0a3aSHans de Goede do { 30554c0a3aSHans de Goede valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num); 31554c0a3aSHans de Goede if (0 == valid) { 32554c0a3aSHans de Goede read_down = true; 33554c0a3aSHans de Goede } 34554c0a3aSHans de Goede } while ((!read_down) && (retry_cnts--)); 35554c0a3aSHans de Goede 36554c0a3aSHans de Goede return read_down; 37554c0a3aSHans de Goede 38554c0a3aSHans de Goede } 39554c0a3aSHans de Goede 40554c0a3aSHans de Goede 41554c0a3aSHans de Goede /***************************************** 42554c0a3aSHans de Goede * H2C Msg format : 43554c0a3aSHans de Goede *| 31 - 8 |7-5 | 4 - 0 | 44554c0a3aSHans de Goede *| h2c_msg |Class |CMD_ID | 45554c0a3aSHans de Goede *| 31-0 | 46554c0a3aSHans de Goede *| Ext msg | 47554c0a3aSHans de Goede * 48554c0a3aSHans de Goede ******************************************/ 49554c0a3aSHans de Goede s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) 50554c0a3aSHans de Goede { 51554c0a3aSHans de Goede u8 h2c_box_num; 52554c0a3aSHans de Goede u32 msgbox_addr; 53554c0a3aSHans de Goede u32 msgbox_ex_addr = 0; 54554c0a3aSHans de Goede struct hal_com_data *pHalData; 55554c0a3aSHans de Goede u32 h2c_cmd = 0; 56554c0a3aSHans de Goede u32 h2c_cmd_ex = 0; 57554c0a3aSHans de Goede s32 ret = _FAIL; 58554c0a3aSHans de Goede 59554c0a3aSHans de Goede padapter = GET_PRIMARY_ADAPTER(padapter); 60554c0a3aSHans de Goede pHalData = GET_HAL_DATA(padapter); 61554c0a3aSHans de Goede if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex))) 62554c0a3aSHans de Goede return ret; 63554c0a3aSHans de Goede 64554c0a3aSHans de Goede if (!pCmdBuffer) { 65554c0a3aSHans de Goede goto exit; 66554c0a3aSHans de Goede } 67554c0a3aSHans de Goede 68554c0a3aSHans de Goede if (CmdLen > RTL8723B_MAX_CMD_LEN) { 69554c0a3aSHans de Goede goto exit; 70554c0a3aSHans de Goede } 71554c0a3aSHans de Goede 72f2e741cbSHariprasad Kelam if (padapter->bSurpriseRemoved) 73554c0a3aSHans de Goede goto exit; 74554c0a3aSHans de Goede 75554c0a3aSHans de Goede /* pay attention to if race condition happened in H2C cmd setting. */ 76554c0a3aSHans de Goede do { 77554c0a3aSHans de Goede h2c_box_num = pHalData->LastHMEBoxNum; 78554c0a3aSHans de Goede 79554c0a3aSHans de Goede if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) { 80554c0a3aSHans de Goede DBG_8192C(" fw read cmd failed...\n"); 81554c0a3aSHans de Goede /* DBG_8192C(" 0x1c0: 0x%8x\n", rtw_read32(padapter, 0x1c0)); */ 82554c0a3aSHans de Goede /* DBG_8192C(" 0x1c4: 0x%8x\n", rtw_read32(padapter, 0x1c4)); */ 83554c0a3aSHans de Goede goto exit; 84554c0a3aSHans de Goede } 85554c0a3aSHans de Goede 86554c0a3aSHans de Goede if (CmdLen <= 3) 87554c0a3aSHans de Goede memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen); 88554c0a3aSHans de Goede else { 89554c0a3aSHans de Goede memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3); 90554c0a3aSHans de Goede memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, CmdLen-3); 91554c0a3aSHans de Goede /* *(u8 *)(&h2c_cmd) |= BIT(7); */ 92554c0a3aSHans de Goede } 93554c0a3aSHans de Goede 94554c0a3aSHans de Goede *(u8 *)(&h2c_cmd) |= ElementID; 95554c0a3aSHans de Goede 96554c0a3aSHans de Goede if (CmdLen > 3) { 97554c0a3aSHans de Goede msgbox_ex_addr = REG_HMEBOX_EXT0_8723B + (h2c_box_num*RTL8723B_EX_MESSAGE_BOX_SIZE); 98554c0a3aSHans de Goede rtw_write32(padapter, msgbox_ex_addr, h2c_cmd_ex); 99554c0a3aSHans de Goede } 100554c0a3aSHans de Goede msgbox_addr = REG_HMEBOX_0 + (h2c_box_num*MESSAGE_BOX_SIZE); 101554c0a3aSHans de Goede rtw_write32(padapter, msgbox_addr, h2c_cmd); 102554c0a3aSHans de Goede 103554c0a3aSHans de Goede /* DBG_8192C("MSG_BOX:%d, CmdLen(%d), CmdID(0x%x), reg:0x%x =>h2c_cmd:0x%.8x, reg:0x%x =>h2c_cmd_ex:0x%.8x\n" */ 104554c0a3aSHans de Goede /* , pHalData->LastHMEBoxNum , CmdLen, ElementID, msgbox_addr, h2c_cmd, msgbox_ex_addr, h2c_cmd_ex); */ 105554c0a3aSHans de Goede 106554c0a3aSHans de Goede pHalData->LastHMEBoxNum = (h2c_box_num+1) % MAX_H2C_BOX_NUMS; 107554c0a3aSHans de Goede 108554c0a3aSHans de Goede } while (0); 109554c0a3aSHans de Goede 110554c0a3aSHans de Goede ret = _SUCCESS; 111554c0a3aSHans de Goede 112554c0a3aSHans de Goede exit: 113554c0a3aSHans de Goede 114554c0a3aSHans de Goede mutex_unlock(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex)); 115554c0a3aSHans de Goede return ret; 116554c0a3aSHans de Goede } 117554c0a3aSHans de Goede 118554c0a3aSHans de Goede static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength) 119554c0a3aSHans de Goede { 120554c0a3aSHans de Goede struct ieee80211_hdr *pwlanhdr; 121554c0a3aSHans de Goede __le16 *fctrl; 122554c0a3aSHans de Goede u32 rate_len, pktlen; 123554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 124554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 125554c0a3aSHans de Goede struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); 126554c0a3aSHans de Goede u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 127554c0a3aSHans de Goede 128554c0a3aSHans de Goede 129554c0a3aSHans de Goede /* DBG_871X("%s\n", __func__); */ 130554c0a3aSHans de Goede 131554c0a3aSHans de Goede pwlanhdr = (struct ieee80211_hdr *)pframe; 132554c0a3aSHans de Goede 133554c0a3aSHans de Goede fctrl = &(pwlanhdr->frame_control); 134554c0a3aSHans de Goede *(fctrl) = 0; 135554c0a3aSHans de Goede 136554c0a3aSHans de Goede memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); 137554c0a3aSHans de Goede memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 138554c0a3aSHans de Goede memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); 139554c0a3aSHans de Goede 140554c0a3aSHans de Goede SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); 141554c0a3aSHans de Goede /* pmlmeext->mgnt_seq++; */ 142554c0a3aSHans de Goede SetFrameSubType(pframe, WIFI_BEACON); 143554c0a3aSHans de Goede 144554c0a3aSHans de Goede pframe += sizeof(struct ieee80211_hdr_3addr); 145554c0a3aSHans de Goede pktlen = sizeof(struct ieee80211_hdr_3addr); 146554c0a3aSHans de Goede 147554c0a3aSHans de Goede /* timestamp will be inserted by hardware */ 148554c0a3aSHans de Goede pframe += 8; 149554c0a3aSHans de Goede pktlen += 8; 150554c0a3aSHans de Goede 151554c0a3aSHans de Goede /* beacon interval: 2 bytes */ 152554c0a3aSHans de Goede memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); 153554c0a3aSHans de Goede 154554c0a3aSHans de Goede pframe += 2; 155554c0a3aSHans de Goede pktlen += 2; 156554c0a3aSHans de Goede 157554c0a3aSHans de Goede /* capability info: 2 bytes */ 158554c0a3aSHans de Goede memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); 159554c0a3aSHans de Goede 160554c0a3aSHans de Goede pframe += 2; 161554c0a3aSHans de Goede pktlen += 2; 162554c0a3aSHans de Goede 163554c0a3aSHans de Goede if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { 164554c0a3aSHans de Goede /* DBG_871X("ie len =%d\n", cur_network->IELength); */ 165554c0a3aSHans de Goede pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fix_ie); 166554c0a3aSHans de Goede memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fix_ie), pktlen); 167554c0a3aSHans de Goede 168554c0a3aSHans de Goede goto _ConstructBeacon; 169554c0a3aSHans de Goede } 170554c0a3aSHans de Goede 171554c0a3aSHans de Goede /* below for ad-hoc mode */ 172554c0a3aSHans de Goede 173554c0a3aSHans de Goede /* SSID */ 1743f15277bSRoss Schmidt pframe = rtw_set_ie(pframe, WLAN_EID_SSID, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); 175554c0a3aSHans de Goede 176554c0a3aSHans de Goede /* supported rates... */ 177554c0a3aSHans de Goede rate_len = rtw_get_rateset_len(cur_network->SupportedRates); 178c34c45edSRoss Schmidt pframe = rtw_set_ie(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); 179554c0a3aSHans de Goede 180554c0a3aSHans de Goede /* DS parameter set */ 1818f6a9446SRoss Schmidt pframe = rtw_set_ie(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); 182554c0a3aSHans de Goede 183554c0a3aSHans de Goede if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { 184554c0a3aSHans de Goede u32 ATIMWindow; 185554c0a3aSHans de Goede /* IBSS Parameter Set... */ 186554c0a3aSHans de Goede /* ATIMWindow = cur->Configuration.ATIMWindow; */ 187554c0a3aSHans de Goede ATIMWindow = 0; 188e6038a48SRoss Schmidt pframe = rtw_set_ie(pframe, WLAN_EID_IBSS_PARAMS, 2, (unsigned char *)(&ATIMWindow), &pktlen); 189554c0a3aSHans de Goede } 190554c0a3aSHans de Goede 191554c0a3aSHans de Goede 192554c0a3aSHans de Goede /* todo: ERP IE */ 193554c0a3aSHans de Goede 194554c0a3aSHans de Goede 195554c0a3aSHans de Goede /* EXTERNDED SUPPORTED RATE */ 196554c0a3aSHans de Goede if (rate_len > 8) 19700f0b682SRoss Schmidt pframe = rtw_set_ie(pframe, WLAN_EID_EXT_SUPP_RATES, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); 198554c0a3aSHans de Goede 199554c0a3aSHans de Goede 200554c0a3aSHans de Goede /* todo:HT for adhoc */ 201554c0a3aSHans de Goede 202554c0a3aSHans de Goede _ConstructBeacon: 203554c0a3aSHans de Goede 204554c0a3aSHans de Goede if ((pktlen + TXDESC_SIZE) > 512) { 205554c0a3aSHans de Goede DBG_871X("beacon frame too large\n"); 206554c0a3aSHans de Goede return; 207554c0a3aSHans de Goede } 208554c0a3aSHans de Goede 209554c0a3aSHans de Goede *pLength = pktlen; 210554c0a3aSHans de Goede 211554c0a3aSHans de Goede /* DBG_871X("%s bcn_sz =%d\n", __func__, pktlen); */ 212554c0a3aSHans de Goede 213554c0a3aSHans de Goede } 214554c0a3aSHans de Goede 215554c0a3aSHans de Goede static void ConstructPSPoll(struct adapter *padapter, u8 *pframe, u32 *pLength) 216554c0a3aSHans de Goede { 217554c0a3aSHans de Goede struct ieee80211_hdr *pwlanhdr; 218554c0a3aSHans de Goede __le16 *fctrl; 219554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 220554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 221554c0a3aSHans de Goede 222554c0a3aSHans de Goede /* DBG_871X("%s\n", __func__); */ 223554c0a3aSHans de Goede 224554c0a3aSHans de Goede pwlanhdr = (struct ieee80211_hdr *)pframe; 225554c0a3aSHans de Goede 226554c0a3aSHans de Goede /* Frame control. */ 227554c0a3aSHans de Goede fctrl = &(pwlanhdr->frame_control); 228554c0a3aSHans de Goede *(fctrl) = 0; 229554c0a3aSHans de Goede SetPwrMgt(fctrl); 230554c0a3aSHans de Goede SetFrameSubType(pframe, WIFI_PSPOLL); 231554c0a3aSHans de Goede 232554c0a3aSHans de Goede /* AID. */ 233554c0a3aSHans de Goede SetDuration(pframe, (pmlmeinfo->aid | 0xc000)); 234554c0a3aSHans de Goede 235554c0a3aSHans de Goede /* BSSID. */ 236554c0a3aSHans de Goede memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 237554c0a3aSHans de Goede 238554c0a3aSHans de Goede /* TA. */ 239554c0a3aSHans de Goede memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 240554c0a3aSHans de Goede 241554c0a3aSHans de Goede *pLength = 16; 242554c0a3aSHans de Goede } 243554c0a3aSHans de Goede 244554c0a3aSHans de Goede static void ConstructNullFunctionData( 245554c0a3aSHans de Goede struct adapter *padapter, 246554c0a3aSHans de Goede u8 *pframe, 247554c0a3aSHans de Goede u32 *pLength, 248554c0a3aSHans de Goede u8 *StaAddr, 249554c0a3aSHans de Goede u8 bQoS, 250554c0a3aSHans de Goede u8 AC, 251554c0a3aSHans de Goede u8 bEosp, 252554c0a3aSHans de Goede u8 bForcePowerSave 253554c0a3aSHans de Goede ) 254554c0a3aSHans de Goede { 255554c0a3aSHans de Goede struct ieee80211_hdr *pwlanhdr; 256554c0a3aSHans de Goede __le16 *fctrl; 257554c0a3aSHans de Goede u32 pktlen; 258554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 259554c0a3aSHans de Goede struct wlan_network *cur_network = &pmlmepriv->cur_network; 260554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 261554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 262554c0a3aSHans de Goede 263554c0a3aSHans de Goede 264554c0a3aSHans de Goede /* DBG_871X("%s:%d\n", __func__, bForcePowerSave); */ 265554c0a3aSHans de Goede 266554c0a3aSHans de Goede pwlanhdr = (struct ieee80211_hdr *)pframe; 267554c0a3aSHans de Goede 268554c0a3aSHans de Goede fctrl = &pwlanhdr->frame_control; 269554c0a3aSHans de Goede *(fctrl) = 0; 270554c0a3aSHans de Goede if (bForcePowerSave) 271554c0a3aSHans de Goede SetPwrMgt(fctrl); 272554c0a3aSHans de Goede 273554c0a3aSHans de Goede switch (cur_network->network.InfrastructureMode) { 274554c0a3aSHans de Goede case Ndis802_11Infrastructure: 275554c0a3aSHans de Goede SetToDs(fctrl); 276554c0a3aSHans de Goede memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 277554c0a3aSHans de Goede memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 278554c0a3aSHans de Goede memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); 279554c0a3aSHans de Goede break; 280554c0a3aSHans de Goede case Ndis802_11APMode: 281554c0a3aSHans de Goede SetFrDs(fctrl); 282554c0a3aSHans de Goede memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); 283554c0a3aSHans de Goede memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 284554c0a3aSHans de Goede memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); 285554c0a3aSHans de Goede break; 286554c0a3aSHans de Goede case Ndis802_11IBSS: 287554c0a3aSHans de Goede default: 288554c0a3aSHans de Goede memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); 289554c0a3aSHans de Goede memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); 290554c0a3aSHans de Goede memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); 291554c0a3aSHans de Goede break; 292554c0a3aSHans de Goede } 293554c0a3aSHans de Goede 294554c0a3aSHans de Goede SetSeqNum(pwlanhdr, 0); 295554c0a3aSHans de Goede 296f2e741cbSHariprasad Kelam if (bQoS) { 297554c0a3aSHans de Goede struct ieee80211_qos_hdr *pwlanqoshdr; 298554c0a3aSHans de Goede 299554c0a3aSHans de Goede SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); 300554c0a3aSHans de Goede 301554c0a3aSHans de Goede pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe; 302554c0a3aSHans de Goede SetPriority(&pwlanqoshdr->qos_ctrl, AC); 303554c0a3aSHans de Goede SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp); 304554c0a3aSHans de Goede 305554c0a3aSHans de Goede pktlen = sizeof(struct ieee80211_qos_hdr); 306554c0a3aSHans de Goede } else { 307554c0a3aSHans de Goede SetFrameSubType(pframe, WIFI_DATA_NULL); 308554c0a3aSHans de Goede 309554c0a3aSHans de Goede pktlen = sizeof(struct ieee80211_hdr_3addr); 310554c0a3aSHans de Goede } 311554c0a3aSHans de Goede 312554c0a3aSHans de Goede *pLength = pktlen; 313554c0a3aSHans de Goede } 314554c0a3aSHans de Goede 315554c0a3aSHans de Goede #ifdef CONFIG_AP_WOWLAN 316554c0a3aSHans de Goede static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) 317554c0a3aSHans de Goede { 318554c0a3aSHans de Goede struct ieee80211_hdr *pwlanhdr; 319554c0a3aSHans de Goede u16 *fctrl; 320554c0a3aSHans de Goede u8 *mac, *bssid; 321554c0a3aSHans de Goede u32 pktlen; 322554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 323554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 324554c0a3aSHans de Goede struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); 325554c0a3aSHans de Goede u8 *pwps_ie; 326554c0a3aSHans de Goede uint wps_ielen; 327554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 328554c0a3aSHans de Goede 329554c0a3aSHans de Goede /* DBG_871X("%s\n", __func__); */ 330554c0a3aSHans de Goede 331554c0a3aSHans de Goede pwlanhdr = (struct ieee80211_hdr *)pframe; 332554c0a3aSHans de Goede 333554c0a3aSHans de Goede mac = myid(&(padapter->eeprompriv)); 334554c0a3aSHans de Goede bssid = cur_network->MacAddress; 335554c0a3aSHans de Goede 336554c0a3aSHans de Goede fctrl = &(pwlanhdr->frame_control); 337554c0a3aSHans de Goede *(fctrl) = 0; 338554c0a3aSHans de Goede memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); 339554c0a3aSHans de Goede memcpy(pwlanhdr->addr2, mac, ETH_ALEN); 340554c0a3aSHans de Goede memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); 341554c0a3aSHans de Goede 342bbda3ac4SRoss Schmidt DBG_871X("%s FW Mac Addr:%pM\n", __func__, MAC_ARG(mac)); 3435e364ea5SRoss Schmidt DBG_871X("%s FW IP Addr:%pI4\n", __func__, IP_ARG(StaAddr)); 344554c0a3aSHans de Goede 345554c0a3aSHans de Goede SetSeqNum(pwlanhdr, 0); 346554c0a3aSHans de Goede SetFrameSubType(fctrl, WIFI_PROBERSP); 347554c0a3aSHans de Goede 348554c0a3aSHans de Goede pktlen = sizeof(struct ieee80211_hdr_3addr); 349554c0a3aSHans de Goede pframe += pktlen; 350554c0a3aSHans de Goede 351554c0a3aSHans de Goede if (cur_network->IELength > MAX_IE_SZ) 352554c0a3aSHans de Goede return; 353554c0a3aSHans de Goede 354554c0a3aSHans de Goede pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, 355554c0a3aSHans de Goede cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); 356554c0a3aSHans de Goede 357554c0a3aSHans de Goede /* inerset & update wps_probe_resp_ie */ 358a029e223SHariprasad Kelam if (pmlmepriv->wps_probe_resp_ie && pwps_ie && (wps_ielen > 0)) { 359554c0a3aSHans de Goede uint wps_offset, remainder_ielen; 360554c0a3aSHans de Goede u8 *premainder_ie; 361554c0a3aSHans de Goede 362554c0a3aSHans de Goede wps_offset = (uint)(pwps_ie - cur_network->IEs); 363554c0a3aSHans de Goede 364554c0a3aSHans de Goede premainder_ie = pwps_ie + wps_ielen; 365554c0a3aSHans de Goede 366554c0a3aSHans de Goede remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; 367554c0a3aSHans de Goede 368554c0a3aSHans de Goede memcpy(pframe, cur_network->IEs, wps_offset); 369554c0a3aSHans de Goede pframe += wps_offset; 370554c0a3aSHans de Goede pktlen += wps_offset; 371554c0a3aSHans de Goede 372554c0a3aSHans de Goede wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ 373554c0a3aSHans de Goede if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) { 374554c0a3aSHans de Goede memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); 375554c0a3aSHans de Goede pframe += wps_ielen+2; 376554c0a3aSHans de Goede pktlen += wps_ielen+2; 377554c0a3aSHans de Goede } 378554c0a3aSHans de Goede 379554c0a3aSHans de Goede if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) { 380554c0a3aSHans de Goede memcpy(pframe, premainder_ie, remainder_ielen); 381554c0a3aSHans de Goede pframe += remainder_ielen; 382554c0a3aSHans de Goede pktlen += remainder_ielen; 383554c0a3aSHans de Goede } 384554c0a3aSHans de Goede } else { 385554c0a3aSHans de Goede memcpy(pframe, cur_network->IEs, cur_network->IELength); 386554c0a3aSHans de Goede pframe += cur_network->IELength; 387554c0a3aSHans de Goede pktlen += cur_network->IELength; 388554c0a3aSHans de Goede } 389554c0a3aSHans de Goede 390554c0a3aSHans de Goede /* retrieve SSID IE from cur_network->Ssid */ 391554c0a3aSHans de Goede { 392554c0a3aSHans de Goede u8 *ssid_ie; 393d495c550SMarco Cesati signed int ssid_ielen; 394d495c550SMarco Cesati signed int ssid_ielen_diff; 395554c0a3aSHans de Goede u8 buf[MAX_IE_SZ]; 396554c0a3aSHans de Goede u8 *ies = pframe + sizeof(struct ieee80211_hdr_3addr); 397554c0a3aSHans de Goede 3983f15277bSRoss Schmidt ssid_ie = rtw_get_ie(ies+_FIXED_IE_LENGTH_, WLAN_EID_SSID, &ssid_ielen, 399554c0a3aSHans de Goede (pframe-ies)-_FIXED_IE_LENGTH_); 400554c0a3aSHans de Goede 401554c0a3aSHans de Goede ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen; 402554c0a3aSHans de Goede 403554c0a3aSHans de Goede if (ssid_ie && cur_network->Ssid.SsidLength) { 404554c0a3aSHans de Goede uint remainder_ielen; 405554c0a3aSHans de Goede u8 *remainder_ie; 406554c0a3aSHans de Goede remainder_ie = ssid_ie+2; 407554c0a3aSHans de Goede remainder_ielen = (pframe-remainder_ie); 408554c0a3aSHans de Goede 409554c0a3aSHans de Goede if (remainder_ielen > MAX_IE_SZ) { 410554c0a3aSHans de Goede DBG_871X_LEVEL(_drv_warning_, FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); 411554c0a3aSHans de Goede remainder_ielen = MAX_IE_SZ; 412554c0a3aSHans de Goede } 413554c0a3aSHans de Goede 414554c0a3aSHans de Goede memcpy(buf, remainder_ie, remainder_ielen); 415554c0a3aSHans de Goede memcpy(remainder_ie+ssid_ielen_diff, buf, remainder_ielen); 416554c0a3aSHans de Goede *(ssid_ie+1) = cur_network->Ssid.SsidLength; 417554c0a3aSHans de Goede memcpy(ssid_ie+2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength); 418554c0a3aSHans de Goede pframe += ssid_ielen_diff; 419554c0a3aSHans de Goede pktlen += ssid_ielen_diff; 420554c0a3aSHans de Goede } 421554c0a3aSHans de Goede } 422554c0a3aSHans de Goede 423554c0a3aSHans de Goede *pLength = pktlen; 424554c0a3aSHans de Goede 425554c0a3aSHans de Goede } 426554c0a3aSHans de Goede #endif /* CONFIG_AP_WOWLAN */ 427554c0a3aSHans de Goede 428e9ed75cfSR Veera Kumar /* 42956faa3c8SR Veera Kumar * To check if reserved page content is destroyed by beacon because beacon 430e9ed75cfSR Veera Kumar * is too large. 431e9ed75cfSR Veera Kumar */ 432554c0a3aSHans de Goede /* 2010.06.23. Added by tynli. */ 433554c0a3aSHans de Goede void CheckFwRsvdPageContent(struct adapter *Adapter) 434554c0a3aSHans de Goede { 435554c0a3aSHans de Goede } 436554c0a3aSHans de Goede 437*dc9a4304SMarco Cesati static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) 438554c0a3aSHans de Goede { 439554c0a3aSHans de Goede u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0}; 440554c0a3aSHans de Goede 441554c0a3aSHans de Goede DBG_871X("8723BRsvdPageLoc: ProbeRsp =%d PsPoll =%d Null =%d QoSNull =%d BTNull =%d\n", 442554c0a3aSHans de Goede rsvdpageloc->LocProbeRsp, rsvdpageloc->LocPsPoll, 443554c0a3aSHans de Goede rsvdpageloc->LocNullData, rsvdpageloc->LocQosNull, 444554c0a3aSHans de Goede rsvdpageloc->LocBTQosNull); 445554c0a3aSHans de Goede 446554c0a3aSHans de Goede SET_8723B_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp); 447554c0a3aSHans de Goede SET_8723B_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); 448554c0a3aSHans de Goede SET_8723B_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); 449554c0a3aSHans de Goede SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); 450554c0a3aSHans de Goede SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull); 451554c0a3aSHans de Goede 452554c0a3aSHans de Goede RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CRsvdPageParm:", u1H2CRsvdPageParm, H2C_RSVDPAGE_LOC_LEN); 453554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); 454554c0a3aSHans de Goede } 455554c0a3aSHans de Goede 456*dc9a4304SMarco Cesati static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) 457554c0a3aSHans de Goede { 458554c0a3aSHans de Goede } 459554c0a3aSHans de Goede 460554c0a3aSHans de Goede #ifdef CONFIG_AP_WOWLAN 461554c0a3aSHans de Goede static void rtl8723b_set_ap_wow_rsvdpage_cmd( 462bb5aedbeSMarco Cesati struct adapter *padapter, struct RSVDPAGE_LOC *rsvdpageloc 463554c0a3aSHans de Goede ) 464554c0a3aSHans de Goede { 465554c0a3aSHans de Goede u8 header; 466554c0a3aSHans de Goede u8 rsvdparm[H2C_AOAC_RSVDPAGE_LOC_LEN] = {0}; 467554c0a3aSHans de Goede 468554c0a3aSHans de Goede header = rtw_read8(padapter, REG_BCNQ_BDNY); 469554c0a3aSHans de Goede 470554c0a3aSHans de Goede DBG_871X("%s: beacon: %d, probeRsp: %d, header:0x%02x\n", __func__, 471554c0a3aSHans de Goede rsvdpageloc->LocApOffloadBCN, 472554c0a3aSHans de Goede rsvdpageloc->LocProbeRsp, 473554c0a3aSHans de Goede header); 474554c0a3aSHans de Goede 475554c0a3aSHans de Goede SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_BCN(rsvdparm, 476554c0a3aSHans de Goede rsvdpageloc->LocApOffloadBCN + header); 477554c0a3aSHans de Goede 478554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_BCN_RSVDPAGE, 479554c0a3aSHans de Goede H2C_BCN_RSVDPAGE_LEN, rsvdparm); 480554c0a3aSHans de Goede 481554c0a3aSHans de Goede msleep(10); 482554c0a3aSHans de Goede 483554c0a3aSHans de Goede memset(&rsvdparm, 0, sizeof(rsvdparm)); 484554c0a3aSHans de Goede 485554c0a3aSHans de Goede SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_ProbeRsp( 486554c0a3aSHans de Goede rsvdparm, 487554c0a3aSHans de Goede rsvdpageloc->LocProbeRsp + header); 488554c0a3aSHans de Goede 489554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_PROBERSP_RSVDPAGE, 490554c0a3aSHans de Goede H2C_PROBERSP_RSVDPAGE_LEN, rsvdparm); 491554c0a3aSHans de Goede 492554c0a3aSHans de Goede msleep(10); 493554c0a3aSHans de Goede } 494554c0a3aSHans de Goede #endif /* CONFIG_AP_WOWLAN */ 495554c0a3aSHans de Goede 496554c0a3aSHans de Goede void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid) 497554c0a3aSHans de Goede { 498554c0a3aSHans de Goede u8 u1H2CMediaStatusRptParm[H2C_MEDIA_STATUS_RPT_LEN] = {0}; 499554c0a3aSHans de Goede u8 macid_end = 0; 500554c0a3aSHans de Goede 501554c0a3aSHans de Goede DBG_871X("%s(): mstatus = %d macid =%d\n", __func__, mstatus, macid); 502554c0a3aSHans de Goede 503554c0a3aSHans de Goede SET_8723B_H2CCMD_MSRRPT_PARM_OPMODE(u1H2CMediaStatusRptParm, mstatus); 504554c0a3aSHans de Goede SET_8723B_H2CCMD_MSRRPT_PARM_MACID_IND(u1H2CMediaStatusRptParm, 0); 505554c0a3aSHans de Goede SET_8723B_H2CCMD_MSRRPT_PARM_MACID(u1H2CMediaStatusRptParm, macid); 506554c0a3aSHans de Goede SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(u1H2CMediaStatusRptParm, macid_end); 507554c0a3aSHans de Goede 508554c0a3aSHans de Goede RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CMediaStatusRptParm:", u1H2CMediaStatusRptParm, H2C_MEDIA_STATUS_RPT_LEN); 509554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm); 510554c0a3aSHans de Goede } 511554c0a3aSHans de Goede 512554c0a3aSHans de Goede void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid, u8 bw, u8 sgi, u32 mask) 513554c0a3aSHans de Goede { 514554c0a3aSHans de Goede u8 u1H2CMacIdConfigParm[H2C_MACID_CFG_LEN] = {0}; 515554c0a3aSHans de Goede 516554c0a3aSHans de Goede DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x\n", __func__, mac_id, raid, bw, mask); 517554c0a3aSHans de Goede 518554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_MACID(u1H2CMacIdConfigParm, mac_id); 519554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_RAID(u1H2CMacIdConfigParm, raid); 520554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_SGI_EN(u1H2CMacIdConfigParm, sgi ? 1 : 0); 521554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_BW(u1H2CMacIdConfigParm, bw); 522554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_RATE_MASK0(u1H2CMacIdConfigParm, (u8)(mask & 0x000000ff)); 523554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_RATE_MASK1(u1H2CMacIdConfigParm, (u8)((mask & 0x0000ff00) >> 8)); 524554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(u1H2CMacIdConfigParm, (u8)((mask & 0x00ff0000) >> 16)); 525554c0a3aSHans de Goede SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(u1H2CMacIdConfigParm, (u8)((mask & 0xff000000) >> 24)); 526554c0a3aSHans de Goede 527554c0a3aSHans de Goede RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CMacIdConfigParm:", u1H2CMacIdConfigParm, H2C_MACID_CFG_LEN); 528554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm); 529554c0a3aSHans de Goede } 530554c0a3aSHans de Goede 5318fce9e28SNishka Dasgupta void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param) 532554c0a3aSHans de Goede { 533554c0a3aSHans de Goede u8 u1H2CRssiSettingParm[H2C_RSSI_SETTING_LEN] = {0}; 534554c0a3aSHans de Goede u8 mac_id = *param; 535554c0a3aSHans de Goede u8 rssi = *(param+2); 536554c0a3aSHans de Goede u8 uldl_state = 0; 537554c0a3aSHans de Goede 538554c0a3aSHans de Goede /* DBG_871X("%s(): param =%.2x-%.2x-%.2x\n", __func__, *param, *(param+1), *(param+2)); */ 539554c0a3aSHans de Goede /* DBG_871X("%s(): mac_id =%d rssi =%d\n", __func__, mac_id, rssi); */ 540554c0a3aSHans de Goede 541554c0a3aSHans de Goede SET_8723B_H2CCMD_RSSI_SETTING_MACID(u1H2CRssiSettingParm, mac_id); 542554c0a3aSHans de Goede SET_8723B_H2CCMD_RSSI_SETTING_RSSI(u1H2CRssiSettingParm, rssi); 543554c0a3aSHans de Goede SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(u1H2CRssiSettingParm, uldl_state); 544554c0a3aSHans de Goede 545554c0a3aSHans de Goede RT_PRINT_DATA(_module_hal_init_c_, _drv_notice_, "u1H2CRssiSettingParm:", u1H2CRssiSettingParm, H2C_RSSI_SETTING_LEN); 546554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, u1H2CRssiSettingParm); 547554c0a3aSHans de Goede } 548554c0a3aSHans de Goede 549554c0a3aSHans de Goede void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode) 550554c0a3aSHans de Goede { 551554c0a3aSHans de Goede int i; 552554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); 553554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; 554554c0a3aSHans de Goede u8 u1H2CPwrModeParm[H2C_PWRMODE_LEN] = {0}; 555554c0a3aSHans de Goede u8 PowerState = 0, awake_intvl = 1, byte5 = 0, rlbm = 0; 556554c0a3aSHans de Goede 557554c0a3aSHans de Goede if (pwrpriv->dtim > 0) 558554c0a3aSHans de Goede DBG_871X("%s(): FW LPS mode = %d, SmartPS =%d, dtim =%d\n", __func__, psmode, pwrpriv->smart_ps, pwrpriv->dtim); 559554c0a3aSHans de Goede else 560554c0a3aSHans de Goede DBG_871X("%s(): FW LPS mode = %d, SmartPS =%d\n", __func__, psmode, pwrpriv->smart_ps); 561554c0a3aSHans de Goede 562554c0a3aSHans de Goede if (pwrpriv->dtim > 0 && pwrpriv->dtim < 16) 563554c0a3aSHans de Goede awake_intvl = pwrpriv->dtim+1;/* DTIM = (awake_intvl - 1) */ 564554c0a3aSHans de Goede else 565554c0a3aSHans de Goede awake_intvl = 3;/* DTIM =2 */ 566554c0a3aSHans de Goede 567554c0a3aSHans de Goede rlbm = 2; 568554c0a3aSHans de Goede 569554c0a3aSHans de Goede if (padapter->registrypriv.wifi_spec == 1) { 570554c0a3aSHans de Goede awake_intvl = 2; 571554c0a3aSHans de Goede rlbm = 2; 572554c0a3aSHans de Goede } 573554c0a3aSHans de Goede 574554c0a3aSHans de Goede if (psmode > 0) { 575606e33ceSNishka Dasgupta if (hal_btcoex_IsBtControlLps(padapter) == true) { 57678c5f096SNishka Dasgupta PowerState = hal_btcoex_RpwmVal(padapter); 577ee8e2ce5SNishka Dasgupta byte5 = hal_btcoex_LpsVal(padapter); 578554c0a3aSHans de Goede 579554c0a3aSHans de Goede if ((rlbm == 2) && (byte5 & BIT(4))) { 580554c0a3aSHans de Goede /* Keep awake interval to 1 to prevent from */ 581554c0a3aSHans de Goede /* decreasing coex performance */ 582554c0a3aSHans de Goede awake_intvl = 2; 583554c0a3aSHans de Goede rlbm = 2; 584554c0a3aSHans de Goede } 585554c0a3aSHans de Goede } else { 586554c0a3aSHans de Goede PowerState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ 587554c0a3aSHans de Goede byte5 = 0x40; 588554c0a3aSHans de Goede } 589554c0a3aSHans de Goede } else { 590554c0a3aSHans de Goede PowerState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ 591554c0a3aSHans de Goede byte5 = 0x40; 592554c0a3aSHans de Goede } 593554c0a3aSHans de Goede 594554c0a3aSHans de Goede SET_8723B_H2CCMD_PWRMODE_PARM_MODE(u1H2CPwrModeParm, (psmode > 0) ? 1 : 0); 595554c0a3aSHans de Goede SET_8723B_H2CCMD_PWRMODE_PARM_SMART_PS(u1H2CPwrModeParm, pwrpriv->smart_ps); 596554c0a3aSHans de Goede SET_8723B_H2CCMD_PWRMODE_PARM_RLBM(u1H2CPwrModeParm, rlbm); 597554c0a3aSHans de Goede SET_8723B_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1H2CPwrModeParm, awake_intvl); 598554c0a3aSHans de Goede SET_8723B_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1H2CPwrModeParm, padapter->registrypriv.uapsd_enable); 599554c0a3aSHans de Goede SET_8723B_H2CCMD_PWRMODE_PARM_PWR_STATE(u1H2CPwrModeParm, PowerState); 600554c0a3aSHans de Goede SET_8723B_H2CCMD_PWRMODE_PARM_BYTE5(u1H2CPwrModeParm, byte5); 601554c0a3aSHans de Goede if (psmode != PS_MODE_ACTIVE) { 602f2e741cbSHariprasad Kelam if (!pmlmeext->adaptive_tsf_done && pmlmeext->bcn_cnt > 0) { 603554c0a3aSHans de Goede u8 ratio_20_delay, ratio_80_delay; 604554c0a3aSHans de Goede 605554c0a3aSHans de Goede /* byte 6 for adaptive_early_32k */ 606554c0a3aSHans de Goede /* 0:3] = DrvBcnEarly (ms) , [4:7] = DrvBcnTimeOut (ms) */ 607554c0a3aSHans de Goede /* 20% for DrvBcnEarly, 80% for DrvBcnTimeOut */ 608554c0a3aSHans de Goede ratio_20_delay = 0; 609554c0a3aSHans de Goede ratio_80_delay = 0; 610554c0a3aSHans de Goede pmlmeext->DrvBcnEarly = 0xff; 611554c0a3aSHans de Goede pmlmeext->DrvBcnTimeOut = 0xff; 612554c0a3aSHans de Goede 613554c0a3aSHans de Goede DBG_871X("%s(): bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); 614554c0a3aSHans de Goede 615554c0a3aSHans de Goede for (i = 0; i < 9; i++) { 616554c0a3aSHans de Goede pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i]*100)/pmlmeext->bcn_cnt; 617554c0a3aSHans de Goede 618554c0a3aSHans de Goede DBG_871X( 619554c0a3aSHans de Goede "%s(): bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d] = %d\n", 620554c0a3aSHans de Goede __func__, 621554c0a3aSHans de Goede i, 622554c0a3aSHans de Goede pmlmeext->bcn_delay_cnt[i], 623554c0a3aSHans de Goede i, 624554c0a3aSHans de Goede pmlmeext->bcn_delay_ratio[i] 625554c0a3aSHans de Goede ); 626554c0a3aSHans de Goede 627554c0a3aSHans de Goede ratio_20_delay += pmlmeext->bcn_delay_ratio[i]; 628554c0a3aSHans de Goede ratio_80_delay += pmlmeext->bcn_delay_ratio[i]; 629554c0a3aSHans de Goede 630554c0a3aSHans de Goede if (ratio_20_delay > 20 && pmlmeext->DrvBcnEarly == 0xff) { 631554c0a3aSHans de Goede pmlmeext->DrvBcnEarly = i; 632554c0a3aSHans de Goede DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, pmlmeext->DrvBcnEarly); 633554c0a3aSHans de Goede } 634554c0a3aSHans de Goede 635554c0a3aSHans de Goede if (ratio_80_delay > 80 && pmlmeext->DrvBcnTimeOut == 0xff) { 636554c0a3aSHans de Goede pmlmeext->DrvBcnTimeOut = i; 637554c0a3aSHans de Goede DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, pmlmeext->DrvBcnTimeOut); 638554c0a3aSHans de Goede } 639554c0a3aSHans de Goede 640554c0a3aSHans de Goede /* reset adaptive_early_32k cnt */ 641554c0a3aSHans de Goede pmlmeext->bcn_delay_cnt[i] = 0; 642554c0a3aSHans de Goede pmlmeext->bcn_delay_ratio[i] = 0; 643554c0a3aSHans de Goede 644554c0a3aSHans de Goede } 645554c0a3aSHans de Goede 646554c0a3aSHans de Goede pmlmeext->bcn_cnt = 0; 647554c0a3aSHans de Goede pmlmeext->adaptive_tsf_done = true; 648554c0a3aSHans de Goede 649554c0a3aSHans de Goede } else { 650554c0a3aSHans de Goede DBG_871X("%s(): DrvBcnEarly = %d\n", __func__, pmlmeext->DrvBcnEarly); 651554c0a3aSHans de Goede DBG_871X("%s(): DrvBcnTimeOut = %d\n", __func__, pmlmeext->DrvBcnTimeOut); 652554c0a3aSHans de Goede } 653554c0a3aSHans de Goede 654554c0a3aSHans de Goede /* offload to FW if fw version > v15.10 655554c0a3aSHans de Goede pmlmeext->DrvBcnEarly = 0; 656554c0a3aSHans de Goede pmlmeext->DrvBcnTimeOut =7; 657554c0a3aSHans de Goede 658554c0a3aSHans de Goede if ((pmlmeext->DrvBcnEarly!= 0Xff) && (pmlmeext->DrvBcnTimeOut!= 0xff)) 659554c0a3aSHans de Goede u1H2CPwrModeParm[H2C_PWRMODE_LEN-1] = BIT(0) | ((pmlmeext->DrvBcnEarly<<1)&0x0E) |((pmlmeext->DrvBcnTimeOut<<4)&0xf0) ; 660554c0a3aSHans de Goede */ 661554c0a3aSHans de Goede 662554c0a3aSHans de Goede } 663554c0a3aSHans de Goede 664f0ef8d3eSNishka Dasgupta hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN); 665554c0a3aSHans de Goede 666554c0a3aSHans de Goede RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPwrModeParm:", u1H2CPwrModeParm, H2C_PWRMODE_LEN); 667554c0a3aSHans de Goede 668554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, u1H2CPwrModeParm); 669554c0a3aSHans de Goede } 670554c0a3aSHans de Goede 671554c0a3aSHans de Goede void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter) 672554c0a3aSHans de Goede { 673554c0a3aSHans de Goede u8 u1H2CPsTuneParm[H2C_PSTUNEPARAM_LEN] = {0}; 674554c0a3aSHans de Goede u8 bcn_to_limit = 10; /* 10 * 100 * awakeinterval (ms) */ 675554c0a3aSHans de Goede u8 dtim_timeout = 5; /* ms wait broadcast data timer */ 676554c0a3aSHans de Goede u8 ps_timeout = 20; /* ms Keep awake when tx */ 677554c0a3aSHans de Goede u8 dtim_period = 3; 678554c0a3aSHans de Goede 679554c0a3aSHans de Goede /* DBG_871X("%s(): FW LPS mode = %d\n", __func__, psmode); */ 680554c0a3aSHans de Goede 681554c0a3aSHans de Goede SET_8723B_H2CCMD_PSTUNE_PARM_BCN_TO_LIMIT(u1H2CPsTuneParm, bcn_to_limit); 682554c0a3aSHans de Goede SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_TIMEOUT(u1H2CPsTuneParm, dtim_timeout); 683554c0a3aSHans de Goede SET_8723B_H2CCMD_PSTUNE_PARM_PS_TIMEOUT(u1H2CPsTuneParm, ps_timeout); 684554c0a3aSHans de Goede SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(u1H2CPsTuneParm, 1); 685554c0a3aSHans de Goede SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(u1H2CPsTuneParm, dtim_period); 686554c0a3aSHans de Goede 687554c0a3aSHans de Goede RT_PRINT_DATA(_module_hal_init_c_, _drv_always_, "u1H2CPsTuneParm:", u1H2CPsTuneParm, H2C_PSTUNEPARAM_LEN); 688554c0a3aSHans de Goede 689554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm); 690554c0a3aSHans de Goede } 691554c0a3aSHans de Goede 692554c0a3aSHans de Goede void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param) 693554c0a3aSHans de Goede { 694554c0a3aSHans de Goede /* BIT0:enable, BIT1:NoConnect32k */ 695554c0a3aSHans de Goede 696554c0a3aSHans de Goede DBG_871X("%s()\n", __func__); 697554c0a3aSHans de Goede 698554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_FWLPS_IN_IPS_, 1, &cmd_param); 699554c0a3aSHans de Goede } 700554c0a3aSHans de Goede 701554c0a3aSHans de Goede #ifdef CONFIG_AP_WOWLAN 702554c0a3aSHans de Goede static void rtl8723b_set_FwAPWoWlanCtrl_Cmd(struct adapter *padapter, u8 bFuncEn) 703554c0a3aSHans de Goede { 704554c0a3aSHans de Goede u8 u1H2CAPWoWlanCtrlParm[H2C_WOWLAN_LEN] = {0}; 705554c0a3aSHans de Goede u8 gpionum = 0, gpio_dur = 0; 706554c0a3aSHans de Goede u8 gpio_high_active = 1; /* 0: low active, 1: high active */ 707554c0a3aSHans de Goede u8 gpio_pulse = bFuncEn; 708554c0a3aSHans de Goede 709554c0a3aSHans de Goede DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); 710554c0a3aSHans de Goede 711554c0a3aSHans de Goede if (bFuncEn) 712554c0a3aSHans de Goede gpio_dur = 16; 713554c0a3aSHans de Goede else 714554c0a3aSHans de Goede gpio_dur = 0; 715554c0a3aSHans de Goede 716554c0a3aSHans de Goede SET_H2CCMD_AP_WOW_GPIO_CTRL_INDEX(u1H2CAPWoWlanCtrlParm, 717554c0a3aSHans de Goede gpionum); 718554c0a3aSHans de Goede SET_H2CCMD_AP_WOW_GPIO_CTRL_PLUS(u1H2CAPWoWlanCtrlParm, 719554c0a3aSHans de Goede gpio_pulse); 720554c0a3aSHans de Goede SET_H2CCMD_AP_WOW_GPIO_CTRL_HIGH_ACTIVE(u1H2CAPWoWlanCtrlParm, 721554c0a3aSHans de Goede gpio_high_active); 722554c0a3aSHans de Goede SET_H2CCMD_AP_WOW_GPIO_CTRL_EN(u1H2CAPWoWlanCtrlParm, 723554c0a3aSHans de Goede bFuncEn); 724554c0a3aSHans de Goede SET_H2CCMD_AP_WOW_GPIO_CTRL_DURATION(u1H2CAPWoWlanCtrlParm, 725554c0a3aSHans de Goede gpio_dur); 726554c0a3aSHans de Goede 727554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_AP_WOW_GPIO_CTRL, 728554c0a3aSHans de Goede H2C_AP_WOW_GPIO_CTRL_LEN, u1H2CAPWoWlanCtrlParm); 729554c0a3aSHans de Goede } 730554c0a3aSHans de Goede 731554c0a3aSHans de Goede static void rtl8723b_set_Fw_AP_Offload_Cmd(struct adapter *padapter, u8 bFuncEn) 732554c0a3aSHans de Goede { 733554c0a3aSHans de Goede u8 u1H2CAPOffloadCtrlParm[H2C_WOWLAN_LEN] = {0}; 734554c0a3aSHans de Goede 735554c0a3aSHans de Goede DBG_871X("%s(): bFuncEn =%d\n", __func__, bFuncEn); 736554c0a3aSHans de Goede 737554c0a3aSHans de Goede SET_H2CCMD_AP_WOWLAN_EN(u1H2CAPOffloadCtrlParm, bFuncEn); 738554c0a3aSHans de Goede 739554c0a3aSHans de Goede FillH2CCmd8723B(padapter, H2C_8723B_AP_OFFLOAD, 740554c0a3aSHans de Goede H2C_AP_OFFLOAD_LEN, u1H2CAPOffloadCtrlParm); 741554c0a3aSHans de Goede } 742554c0a3aSHans de Goede 7437a9a7332SNishka Dasgupta void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable) 744554c0a3aSHans de Goede { 745554c0a3aSHans de Goede DBG_871X_LEVEL(_drv_always_, "+%s()+: enable =%d\n", __func__, enable); 746554c0a3aSHans de Goede if (enable) { 747554c0a3aSHans de Goede rtl8723b_set_FwJoinBssRpt_cmd(padapter, RT_MEDIA_CONNECT); 748554c0a3aSHans de Goede issue_beacon(padapter, 0); 749554c0a3aSHans de Goede } 750554c0a3aSHans de Goede 751554c0a3aSHans de Goede rtl8723b_set_FwAPWoWlanCtrl_Cmd(padapter, enable); 752554c0a3aSHans de Goede msleep(10); 753554c0a3aSHans de Goede rtl8723b_set_Fw_AP_Offload_Cmd(padapter, enable); 754554c0a3aSHans de Goede msleep(10); 755554c0a3aSHans de Goede DBG_871X_LEVEL(_drv_always_, "-%s()-\n", __func__); 756554c0a3aSHans de Goede } 757554c0a3aSHans de Goede #endif /* CONFIG_AP_WOWLAN */ 758554c0a3aSHans de Goede 759e9ed75cfSR Veera Kumar /* 760e9ed75cfSR Veera Kumar * Description: Fill the reserved packets that FW will use to RSVD page. 761e9ed75cfSR Veera Kumar * Now we just send 4 types packet to rsvd page. 762e9ed75cfSR Veera Kumar * (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. 763e9ed75cfSR Veera Kumar * 764e9ed75cfSR Veera Kumar * Input: 765e9ed75cfSR Veera Kumar * 766e9ed75cfSR Veera Kumar * bDLFinished - false: At the first time we will send all the packets as 76756faa3c8SR Veera Kumar * a large packet to Hw, so we need to set the packet length to total length. 768e9ed75cfSR Veera Kumar * 769e9ed75cfSR Veera Kumar * true: At the second time, we should send the first packet (default:beacon) 77056faa3c8SR Veera Kumar * to Hw again and set the length in descriptor to the real beacon length. 771e9ed75cfSR Veera Kumar */ 772554c0a3aSHans de Goede /* 2009.10.15 by tynli. */ 773554c0a3aSHans de Goede static void rtl8723b_set_FwRsvdPagePkt( 774554c0a3aSHans de Goede struct adapter *padapter, bool bDLFinished 775554c0a3aSHans de Goede ) 776554c0a3aSHans de Goede { 777554c0a3aSHans de Goede struct xmit_frame *pcmdframe; 778554c0a3aSHans de Goede struct pkt_attrib *pattrib; 779554c0a3aSHans de Goede struct xmit_priv *pxmitpriv; 780554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext; 781554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo; 782554c0a3aSHans de Goede struct pwrctrl_priv *pwrctl; 783554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &padapter->mlmepriv; 784554c0a3aSHans de Goede u32 BeaconLength = 0, PSPollLength = 0; 785554c0a3aSHans de Goede u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0; 786554c0a3aSHans de Goede u8 *ReservedPagePacket; 787554c0a3aSHans de Goede u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; 788554c0a3aSHans de Goede u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; 789554c0a3aSHans de Goede u16 BufIndex, PageSize = 128; 790554c0a3aSHans de Goede u32 TotalPacketLen, MaxRsvdPageBufSize = 0; 791ada3334fSFabio Aiuto 792*dc9a4304SMarco Cesati struct rsvdpage_loc RsvdPageLoc; 793554c0a3aSHans de Goede 794554c0a3aSHans de Goede /* DBG_871X("%s---->\n", __func__); */ 795554c0a3aSHans de Goede 796554c0a3aSHans de Goede pxmitpriv = &padapter->xmitpriv; 797554c0a3aSHans de Goede pmlmeext = &padapter->mlmeextpriv; 798554c0a3aSHans de Goede pmlmeinfo = &pmlmeext->mlmext_info; 799554c0a3aSHans de Goede pwrctl = adapter_to_pwrctl(padapter); 800554c0a3aSHans de Goede 801554c0a3aSHans de Goede RsvdPageNum = BCNQ_PAGE_NUM_8723B + WOWLAN_PAGE_NUM_8723B; 802554c0a3aSHans de Goede MaxRsvdPageBufSize = RsvdPageNum*PageSize; 803554c0a3aSHans de Goede 804554c0a3aSHans de Goede pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); 8057cd6f4b0SHimadri Pandya if (!pcmdframe) { 806554c0a3aSHans de Goede DBG_871X("%s: alloc ReservedPagePacket fail!\n", __func__); 807554c0a3aSHans de Goede return; 808554c0a3aSHans de Goede } 809554c0a3aSHans de Goede 810554c0a3aSHans de Goede ReservedPagePacket = pcmdframe->buf_addr; 811*dc9a4304SMarco Cesati memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc)); 812554c0a3aSHans de Goede 813554c0a3aSHans de Goede /* 3 (1) beacon */ 814554c0a3aSHans de Goede BufIndex = TxDescOffset; 815554c0a3aSHans de Goede ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); 816554c0a3aSHans de Goede 817554c0a3aSHans de Goede /* When we count the first page size, we need to reserve description size for the RSVD */ 818554c0a3aSHans de Goede /* packet, it will be filled in front of the packet in TXPKTBUF. */ 819554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); 820554c0a3aSHans de Goede /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ 821554c0a3aSHans de Goede if (CurtPktPageNum == 1) 822554c0a3aSHans de Goede CurtPktPageNum += 1; 823554c0a3aSHans de Goede 824554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 825554c0a3aSHans de Goede 826554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 827554c0a3aSHans de Goede 828554c0a3aSHans de Goede /* 3 (2) ps-poll */ 829554c0a3aSHans de Goede RsvdPageLoc.LocPsPoll = TotalPageNum; 830554c0a3aSHans de Goede ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength); 831554c0a3aSHans de Goede rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false, false); 832554c0a3aSHans de Goede 833554c0a3aSHans de Goede /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: PS-POLL %p %d\n", */ 834554c0a3aSHans de Goede /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (PSPollLength+TxDescLen)); */ 835554c0a3aSHans de Goede 836554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + PSPollLength); 837554c0a3aSHans de Goede 838554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 839554c0a3aSHans de Goede 840554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 841554c0a3aSHans de Goede 842554c0a3aSHans de Goede /* 3 (3) null data */ 843554c0a3aSHans de Goede RsvdPageLoc.LocNullData = TotalPageNum; 844554c0a3aSHans de Goede ConstructNullFunctionData( 845554c0a3aSHans de Goede padapter, 846554c0a3aSHans de Goede &ReservedPagePacket[BufIndex], 847554c0a3aSHans de Goede &NullDataLength, 848554c0a3aSHans de Goede get_my_bssid(&pmlmeinfo->network), 849554c0a3aSHans de Goede false, 0, 0, false 850554c0a3aSHans de Goede ); 851554c0a3aSHans de Goede rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false, false); 852554c0a3aSHans de Goede 853554c0a3aSHans de Goede /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: NULL DATA %p %d\n", */ 854554c0a3aSHans de Goede /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (NullDataLength+TxDescLen)); */ 855554c0a3aSHans de Goede 856554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + NullDataLength); 857554c0a3aSHans de Goede 858554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 859554c0a3aSHans de Goede 860554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 861554c0a3aSHans de Goede 862554c0a3aSHans de Goede /* 3 (5) Qos null data */ 863554c0a3aSHans de Goede RsvdPageLoc.LocQosNull = TotalPageNum; 864554c0a3aSHans de Goede ConstructNullFunctionData( 865554c0a3aSHans de Goede padapter, 866554c0a3aSHans de Goede &ReservedPagePacket[BufIndex], 867554c0a3aSHans de Goede &QosNullLength, 868554c0a3aSHans de Goede get_my_bssid(&pmlmeinfo->network), 869554c0a3aSHans de Goede true, 0, 0, false 870554c0a3aSHans de Goede ); 871554c0a3aSHans de Goede rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false, false); 872554c0a3aSHans de Goede 873554c0a3aSHans de Goede /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ 874554c0a3aSHans de Goede /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (QosNullLength+TxDescLen)); */ 875554c0a3aSHans de Goede 876554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + QosNullLength); 877554c0a3aSHans de Goede 878554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 879554c0a3aSHans de Goede 880554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 881554c0a3aSHans de Goede 882554c0a3aSHans de Goede /* 3 (6) BT Qos null data */ 883554c0a3aSHans de Goede RsvdPageLoc.LocBTQosNull = TotalPageNum; 884554c0a3aSHans de Goede ConstructNullFunctionData( 885554c0a3aSHans de Goede padapter, 886554c0a3aSHans de Goede &ReservedPagePacket[BufIndex], 887554c0a3aSHans de Goede &BTQosNullLength, 888554c0a3aSHans de Goede get_my_bssid(&pmlmeinfo->network), 889554c0a3aSHans de Goede true, 0, 0, false 890554c0a3aSHans de Goede ); 891554c0a3aSHans de Goede rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false); 892554c0a3aSHans de Goede 893554c0a3aSHans de Goede /* DBG_871X("%s(): HW_VAR_SET_TX_CMD: BT QOS NULL DATA %p %d\n", */ 894554c0a3aSHans de Goede /* __func__, &ReservedPagePacket[BufIndex-TxDescLen], (BTQosNullLength+TxDescLen)); */ 895554c0a3aSHans de Goede 896554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength); 897554c0a3aSHans de Goede 898554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 899554c0a3aSHans de Goede 900554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 901554c0a3aSHans de Goede 902554c0a3aSHans de Goede TotalPacketLen = BufIndex + BTQosNullLength; 903554c0a3aSHans de Goede 904554c0a3aSHans de Goede if (TotalPacketLen > MaxRsvdPageBufSize) { 905554c0a3aSHans de Goede DBG_871X("%s(): ERROR: The rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", __func__, 906554c0a3aSHans de Goede TotalPacketLen, MaxRsvdPageBufSize); 907554c0a3aSHans de Goede goto error; 908554c0a3aSHans de Goede } else { 909554c0a3aSHans de Goede /* update attribute */ 910554c0a3aSHans de Goede pattrib = &pcmdframe->attrib; 911554c0a3aSHans de Goede update_mgntframe_attrib(padapter, pattrib); 912554c0a3aSHans de Goede pattrib->qsel = 0x10; 913554c0a3aSHans de Goede pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; 914554c0a3aSHans de Goede dump_mgntframe_and_wait(padapter, pcmdframe, 100); 915554c0a3aSHans de Goede } 916554c0a3aSHans de Goede 917554c0a3aSHans de Goede DBG_871X("%s: Set RSVD page location to Fw , TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); 918554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, _FW_LINKED)) { 919554c0a3aSHans de Goede rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); 920554c0a3aSHans de Goede rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); 921554c0a3aSHans de Goede } else { 922554c0a3aSHans de Goede rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); 923554c0a3aSHans de Goede } 924554c0a3aSHans de Goede return; 925554c0a3aSHans de Goede 926554c0a3aSHans de Goede error: 927554c0a3aSHans de Goede 928554c0a3aSHans de Goede rtw_free_xmitframe(pxmitpriv, pcmdframe); 929554c0a3aSHans de Goede } 930554c0a3aSHans de Goede 931554c0a3aSHans de Goede #ifdef CONFIG_AP_WOWLAN 932e9ed75cfSR Veera Kumar /* 933e9ed75cfSR Veera Kumar * Description: Fill the reserved packets that FW will use to RSVD page. 934e9ed75cfSR Veera Kumar * Now we just send 2 types packet to rsvd page. (1)Beacon, (2)ProbeRsp. 935e9ed75cfSR Veera Kumar * 936e9ed75cfSR Veera Kumar * Input: bDLFinished 937e9ed75cfSR Veera Kumar * 938e9ed75cfSR Veera Kumar * false: At the first time we will send all the packets as a large packet to 93956faa3c8SR Veera Kumar * Hw, so we need to set the packet length to total length. 940e9ed75cfSR Veera Kumar * 941e9ed75cfSR Veera Kumar * true: At the second time, we should send the first packet (default:beacon) 94256faa3c8SR Veera Kumar * to Hw again and set the length in descriptor to the real beacon length. 943e9ed75cfSR Veera Kumar */ 944554c0a3aSHans de Goede /* 2009.10.15 by tynli. */ 945554c0a3aSHans de Goede static void rtl8723b_set_AP_FwRsvdPagePkt( 946554c0a3aSHans de Goede struct adapter *padapter, bool bDLFinished 947554c0a3aSHans de Goede ) 948554c0a3aSHans de Goede { 949554c0a3aSHans de Goede struct hal_com_data *pHalData; 950554c0a3aSHans de Goede struct xmit_frame *pcmdframe; 951554c0a3aSHans de Goede struct pkt_attrib *pattrib; 952554c0a3aSHans de Goede struct xmit_priv *pxmitpriv; 953554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext; 954554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo; 955554c0a3aSHans de Goede struct pwrctrl_priv *pwrctl; 956554c0a3aSHans de Goede u32 BeaconLength = 0, ProbeRspLength = 0; 957554c0a3aSHans de Goede u8 *ReservedPagePacket; 958554c0a3aSHans de Goede u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; 959554c0a3aSHans de Goede u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; 960554c0a3aSHans de Goede u8 currentip[4]; 961554c0a3aSHans de Goede u16 BufIndex, PageSize = 128; 962554c0a3aSHans de Goede u32 TotalPacketLen = 0, MaxRsvdPageBufSize = 0; 963bb5aedbeSMarco Cesati struct RSVDPAGE_LOC RsvdPageLoc; 964554c0a3aSHans de Goede 965554c0a3aSHans de Goede /* DBG_871X("%s---->\n", __func__); */ 966554c0a3aSHans de Goede DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d\n", 967554c0a3aSHans de Goede FUNC_ADPT_ARG(padapter), get_iface_type(padapter)); 968554c0a3aSHans de Goede 969554c0a3aSHans de Goede pHalData = GET_HAL_DATA(padapter); 970554c0a3aSHans de Goede pxmitpriv = &padapter->xmitpriv; 971554c0a3aSHans de Goede pmlmeext = &padapter->mlmeextpriv; 972554c0a3aSHans de Goede pmlmeinfo = &pmlmeext->mlmext_info; 973554c0a3aSHans de Goede pwrctl = adapter_to_pwrctl(padapter); 974554c0a3aSHans de Goede 975554c0a3aSHans de Goede RsvdPageNum = BCNQ_PAGE_NUM_8723B + AP_WOWLAN_PAGE_NUM_8723B; 976554c0a3aSHans de Goede MaxRsvdPageBufSize = RsvdPageNum*PageSize; 977554c0a3aSHans de Goede 978554c0a3aSHans de Goede pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); 9797cd6f4b0SHimadri Pandya if (!pcmdframe) { 980554c0a3aSHans de Goede DBG_871X("%s: alloc ReservedPagePacket fail!\n", __func__); 981554c0a3aSHans de Goede return; 982554c0a3aSHans de Goede } 983554c0a3aSHans de Goede 984554c0a3aSHans de Goede ReservedPagePacket = pcmdframe->buf_addr; 985bb5aedbeSMarco Cesati memset(&RsvdPageLoc, 0, sizeof(struct RSVDPAGE_LOC)); 986554c0a3aSHans de Goede 987554c0a3aSHans de Goede /* 3 (1) beacon */ 988554c0a3aSHans de Goede BufIndex = TxDescOffset; 989554c0a3aSHans de Goede ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); 990554c0a3aSHans de Goede 991554c0a3aSHans de Goede /* When we count the first page size, we need to reserve description size for the RSVD */ 992554c0a3aSHans de Goede /* packet, it will be filled in front of the packet in TXPKTBUF. */ 993554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); 994554c0a3aSHans de Goede /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ 995554c0a3aSHans de Goede if (CurtPktPageNum == 1) 996554c0a3aSHans de Goede CurtPktPageNum += 1; 997554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 998554c0a3aSHans de Goede 999554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 1000554c0a3aSHans de Goede 1001554c0a3aSHans de Goede /* 2 (4) probe response */ 1002554c0a3aSHans de Goede RsvdPageLoc.LocProbeRsp = TotalPageNum; 1003554c0a3aSHans de Goede 1004554c0a3aSHans de Goede rtw_get_current_ip_address(padapter, currentip); 1005554c0a3aSHans de Goede 1006554c0a3aSHans de Goede ConstructProbeRsp( 1007554c0a3aSHans de Goede padapter, 1008554c0a3aSHans de Goede &ReservedPagePacket[BufIndex], 1009554c0a3aSHans de Goede &ProbeRspLength, 1010554c0a3aSHans de Goede currentip, 1011554c0a3aSHans de Goede false); 1012554c0a3aSHans de Goede rtl8723b_fill_fake_txdesc(padapter, 1013554c0a3aSHans de Goede &ReservedPagePacket[BufIndex-TxDescLen], 1014554c0a3aSHans de Goede ProbeRspLength, 1015554c0a3aSHans de Goede false, false, false); 1016554c0a3aSHans de Goede 1017554c0a3aSHans de Goede DBG_871X("%s(): HW_VAR_SET_TX_CMD: PROBE RSP %p %d\n", 1018554c0a3aSHans de Goede __func__, &ReservedPagePacket[BufIndex-TxDescLen], 1019554c0a3aSHans de Goede (ProbeRspLength+TxDescLen)); 1020554c0a3aSHans de Goede 1021554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + ProbeRspLength); 1022554c0a3aSHans de Goede 1023554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 1024554c0a3aSHans de Goede 1025554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 1026554c0a3aSHans de Goede 1027554c0a3aSHans de Goede TotalPacketLen = BufIndex + ProbeRspLength; 1028554c0a3aSHans de Goede 1029554c0a3aSHans de Goede if (TotalPacketLen > MaxRsvdPageBufSize) { 1030554c0a3aSHans de Goede DBG_871X("%s(): ERROR: The rsvd page size is not enough \ 1031554c0a3aSHans de Goede !!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", 1032554c0a3aSHans de Goede __func__, TotalPacketLen, MaxRsvdPageBufSize); 1033554c0a3aSHans de Goede goto error; 1034554c0a3aSHans de Goede } else { 1035554c0a3aSHans de Goede /* update attribute */ 1036554c0a3aSHans de Goede pattrib = &pcmdframe->attrib; 1037554c0a3aSHans de Goede update_mgntframe_attrib(padapter, pattrib); 1038554c0a3aSHans de Goede pattrib->qsel = 0x10; 1039554c0a3aSHans de Goede pattrib->pktlen = TotalPacketLen - TxDescOffset; 1040554c0a3aSHans de Goede pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; 1041554c0a3aSHans de Goede dump_mgntframe_and_wait(padapter, pcmdframe, 100); 1042554c0a3aSHans de Goede } 1043554c0a3aSHans de Goede 1044554c0a3aSHans de Goede DBG_871X("%s: Set RSVD page location to Fw , TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); 1045554c0a3aSHans de Goede rtl8723b_set_ap_wow_rsvdpage_cmd(padapter, &RsvdPageLoc); 1046554c0a3aSHans de Goede 1047554c0a3aSHans de Goede return; 1048554c0a3aSHans de Goede error: 1049554c0a3aSHans de Goede rtw_free_xmitframe(pxmitpriv, pcmdframe); 1050554c0a3aSHans de Goede } 1051554c0a3aSHans de Goede #endif /* CONFIG_AP_WOWLAN */ 1052554c0a3aSHans de Goede 1053554c0a3aSHans de Goede void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) 1054554c0a3aSHans de Goede { 1055554c0a3aSHans de Goede struct hal_com_data *pHalData = GET_HAL_DATA(padapter); 1056554c0a3aSHans de Goede #ifdef CONFIG_AP_WOWLAN 1057554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); 1058554c0a3aSHans de Goede #endif 1059554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); 1060554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 1061554c0a3aSHans de Goede bool bcn_valid = false; 1062554c0a3aSHans de Goede u8 DLBcnCount = 0; 1063554c0a3aSHans de Goede u32 poll = 0; 1064554c0a3aSHans de Goede u8 val8; 1065554c0a3aSHans de Goede 1066554c0a3aSHans de Goede DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d mstatus(%x)\n", 1067554c0a3aSHans de Goede FUNC_ADPT_ARG(padapter), get_iface_type(padapter), mstatus); 1068554c0a3aSHans de Goede 1069554c0a3aSHans de Goede if (mstatus == RT_MEDIA_CONNECT) { 1070554c0a3aSHans de Goede bool bRecover = false; 1071554c0a3aSHans de Goede u8 v8; 1072554c0a3aSHans de Goede 1073554c0a3aSHans de Goede /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ 1074554c0a3aSHans de Goede /* Suggested by filen. Added by tynli. */ 1075554c0a3aSHans de Goede rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); 1076554c0a3aSHans de Goede 1077554c0a3aSHans de Goede /* set REG_CR bit 8 */ 1078554c0a3aSHans de Goede v8 = rtw_read8(padapter, REG_CR+1); 1079554c0a3aSHans de Goede v8 |= BIT(0); /* ENSWBCN */ 1080554c0a3aSHans de Goede rtw_write8(padapter, REG_CR+1, v8); 1081554c0a3aSHans de Goede 1082554c0a3aSHans de Goede /* Disable Hw protection for a time which revserd for Hw sending beacon. */ 1083554c0a3aSHans de Goede /* Fix download reserved page packet fail that access collision with the protection time. */ 1084554c0a3aSHans de Goede /* 2010.05.11. Added by tynli. */ 1085554c0a3aSHans de Goede val8 = rtw_read8(padapter, REG_BCN_CTRL); 1086554c0a3aSHans de Goede val8 &= ~EN_BCN_FUNCTION; 1087554c0a3aSHans de Goede val8 |= DIS_TSF_UDT; 1088554c0a3aSHans de Goede rtw_write8(padapter, REG_BCN_CTRL, val8); 1089554c0a3aSHans de Goede 1090554c0a3aSHans de Goede /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ 1091554c0a3aSHans de Goede if (pHalData->RegFwHwTxQCtrl & BIT(6)) 1092554c0a3aSHans de Goede bRecover = true; 1093554c0a3aSHans de Goede 1094554c0a3aSHans de Goede /* To tell Hw the packet is not a real beacon frame. */ 1095554c0a3aSHans de Goede rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6)); 1096554c0a3aSHans de Goede pHalData->RegFwHwTxQCtrl &= ~BIT(6); 1097554c0a3aSHans de Goede 1098554c0a3aSHans de Goede /* Clear beacon valid check bit. */ 1099554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); 1100554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); 1101554c0a3aSHans de Goede 1102554c0a3aSHans de Goede DLBcnCount = 0; 1103554c0a3aSHans de Goede poll = 0; 1104554c0a3aSHans de Goede do { 1105554c0a3aSHans de Goede #ifdef CONFIG_AP_WOWLAN 1106554c0a3aSHans de Goede if (pwrpriv->wowlan_ap_mode) 1107554c0a3aSHans de Goede rtl8723b_set_AP_FwRsvdPagePkt(padapter, 0); 1108554c0a3aSHans de Goede else 1109554c0a3aSHans de Goede rtl8723b_set_FwRsvdPagePkt(padapter, 0); 1110554c0a3aSHans de Goede #else 1111554c0a3aSHans de Goede /* download rsvd page. */ 1112554c0a3aSHans de Goede rtl8723b_set_FwRsvdPagePkt(padapter, 0); 1113554c0a3aSHans de Goede #endif 1114554c0a3aSHans de Goede DLBcnCount++; 1115554c0a3aSHans de Goede do { 1116554c0a3aSHans de Goede yield(); 1117554c0a3aSHans de Goede /* mdelay(10); */ 1118554c0a3aSHans de Goede /* check rsvd page download OK. */ 1119554c0a3aSHans de Goede rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid)); 1120554c0a3aSHans de Goede poll++; 1121554c0a3aSHans de Goede } while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 1122554c0a3aSHans de Goede 1123554c0a3aSHans de Goede } while (!bcn_valid && DLBcnCount <= 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 1124554c0a3aSHans de Goede 1125554c0a3aSHans de Goede if (padapter->bSurpriseRemoved || padapter->bDriverStopped) { 1126554c0a3aSHans de Goede } else if (!bcn_valid) 1127d0cc39cdSRoss Schmidt DBG_871X("%s: 1 DL RSVD page failed! DLBcnCount:%u, poll:%u\n", 1128554c0a3aSHans de Goede ADPT_ARG(padapter), DLBcnCount, poll); 1129554c0a3aSHans de Goede else { 1130554c0a3aSHans de Goede struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); 1131554c0a3aSHans de Goede pwrctl->fw_psmode_iface_id = padapter->iface_id; 1132d0cc39cdSRoss Schmidt DBG_871X("%s: 1 DL RSVD page success! DLBcnCount:%u, poll:%u\n", 1133554c0a3aSHans de Goede ADPT_ARG(padapter), DLBcnCount, poll); 1134554c0a3aSHans de Goede } 1135554c0a3aSHans de Goede 1136554c0a3aSHans de Goede /* 2010.05.11. Added by tynli. */ 1137554c0a3aSHans de Goede val8 = rtw_read8(padapter, REG_BCN_CTRL); 1138554c0a3aSHans de Goede val8 |= EN_BCN_FUNCTION; 1139554c0a3aSHans de Goede val8 &= ~DIS_TSF_UDT; 1140554c0a3aSHans de Goede rtw_write8(padapter, REG_BCN_CTRL, val8); 1141554c0a3aSHans de Goede 1142554c0a3aSHans de Goede /* To make sure that if there exists an adapter which would like to send beacon. */ 1143554c0a3aSHans de Goede /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ 1144554c0a3aSHans de Goede /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ 1145554c0a3aSHans de Goede /* the beacon cannot be sent by HW. */ 1146554c0a3aSHans de Goede /* 2010.06.23. Added by tynli. */ 1147554c0a3aSHans de Goede if (bRecover) { 1148554c0a3aSHans de Goede rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6)); 1149554c0a3aSHans de Goede pHalData->RegFwHwTxQCtrl |= BIT(6); 1150554c0a3aSHans de Goede } 1151554c0a3aSHans de Goede 1152554c0a3aSHans de Goede /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ 1153554c0a3aSHans de Goede v8 = rtw_read8(padapter, REG_CR+1); 1154554c0a3aSHans de Goede v8 &= ~BIT(0); /* ~ENSWBCN */ 1155554c0a3aSHans de Goede rtw_write8(padapter, REG_CR+1, v8); 1156554c0a3aSHans de Goede } 1157554c0a3aSHans de Goede } 1158554c0a3aSHans de Goede 1159554c0a3aSHans de Goede void rtl8723b_set_FwJoinBssRpt_cmd(struct adapter *padapter, u8 mstatus) 1160554c0a3aSHans de Goede { 1161554c0a3aSHans de Goede if (mstatus == 1) 1162554c0a3aSHans de Goede rtl8723b_download_rsvd_page(padapter, RT_MEDIA_CONNECT); 1163554c0a3aSHans de Goede } 1164554c0a3aSHans de Goede 1165554c0a3aSHans de Goede /* arg[0] = macid */ 1166554c0a3aSHans de Goede /* arg[1] = raid */ 1167554c0a3aSHans de Goede /* arg[2] = shortGIrate */ 1168554c0a3aSHans de Goede /* arg[3] = init_rate */ 1169554c0a3aSHans de Goede void rtl8723b_Add_RateATid( 1170554c0a3aSHans de Goede struct adapter *padapter, 1171554c0a3aSHans de Goede u32 bitmap, 1172554c0a3aSHans de Goede u8 *arg, 1173554c0a3aSHans de Goede u8 rssi_level 1174554c0a3aSHans de Goede ) 1175554c0a3aSHans de Goede { 1176554c0a3aSHans de Goede struct hal_com_data *pHalData = GET_HAL_DATA(padapter); 1177554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; 1178554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); 1179554c0a3aSHans de Goede struct sta_info *psta; 1180554c0a3aSHans de Goede u8 mac_id = arg[0]; 1181554c0a3aSHans de Goede u8 raid = arg[1]; 1182554c0a3aSHans de Goede u8 shortGI = arg[2]; 1183554c0a3aSHans de Goede u8 bw; 1184554c0a3aSHans de Goede u32 mask = bitmap&0x0FFFFFFF; 1185554c0a3aSHans de Goede 1186554c0a3aSHans de Goede psta = pmlmeinfo->FW_sta_info[mac_id].psta; 11877cd6f4b0SHimadri Pandya if (!psta) 1188554c0a3aSHans de Goede return; 1189554c0a3aSHans de Goede 1190554c0a3aSHans de Goede bw = psta->bw_mode; 1191554c0a3aSHans de Goede 1192554c0a3aSHans de Goede if (rssi_level != DM_RATR_STA_INIT) 1193554c0a3aSHans de Goede mask = ODM_Get_Rate_Bitmap(&pHalData->odmpriv, mac_id, mask, rssi_level); 1194554c0a3aSHans de Goede 1195554c0a3aSHans de Goede DBG_871X("%s(): mac_id =%d raid = 0x%x bw =%d mask = 0x%x\n", __func__, mac_id, raid, bw, mask); 1196554c0a3aSHans de Goede rtl8723b_set_FwMacIdConfig_cmd(padapter, mac_id, raid, bw, shortGI, mask); 1197554c0a3aSHans de Goede } 1198554c0a3aSHans de Goede 1199554c0a3aSHans de Goede static void ConstructBtNullFunctionData( 1200554c0a3aSHans de Goede struct adapter *padapter, 1201554c0a3aSHans de Goede u8 *pframe, 1202554c0a3aSHans de Goede u32 *pLength, 1203554c0a3aSHans de Goede u8 *StaAddr, 1204554c0a3aSHans de Goede u8 bQoS, 1205554c0a3aSHans de Goede u8 AC, 1206554c0a3aSHans de Goede u8 bEosp, 1207554c0a3aSHans de Goede u8 bForcePowerSave 1208554c0a3aSHans de Goede ) 1209554c0a3aSHans de Goede { 1210554c0a3aSHans de Goede struct ieee80211_hdr *pwlanhdr; 1211554c0a3aSHans de Goede __le16 *fctrl; 1212554c0a3aSHans de Goede u32 pktlen; 1213554c0a3aSHans de Goede u8 bssid[ETH_ALEN]; 1214554c0a3aSHans de Goede 1215554c0a3aSHans de Goede 1216554c0a3aSHans de Goede DBG_871X("+" FUNC_ADPT_FMT ": qos =%d eosp =%d ps =%d\n", 1217554c0a3aSHans de Goede FUNC_ADPT_ARG(padapter), bQoS, bEosp, bForcePowerSave); 1218554c0a3aSHans de Goede 1219554c0a3aSHans de Goede pwlanhdr = (struct ieee80211_hdr *)pframe; 1220554c0a3aSHans de Goede 12217cd6f4b0SHimadri Pandya if (!StaAddr) { 1222554c0a3aSHans de Goede memcpy(bssid, myid(&padapter->eeprompriv), ETH_ALEN); 1223554c0a3aSHans de Goede StaAddr = bssid; 1224554c0a3aSHans de Goede } 1225554c0a3aSHans de Goede 1226554c0a3aSHans de Goede fctrl = &pwlanhdr->frame_control; 1227554c0a3aSHans de Goede *fctrl = 0; 1228554c0a3aSHans de Goede if (bForcePowerSave) 1229554c0a3aSHans de Goede SetPwrMgt(fctrl); 1230554c0a3aSHans de Goede 1231554c0a3aSHans de Goede SetFrDs(fctrl); 1232554c0a3aSHans de Goede memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); 1233554c0a3aSHans de Goede memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); 1234554c0a3aSHans de Goede memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); 1235554c0a3aSHans de Goede 1236554c0a3aSHans de Goede SetDuration(pwlanhdr, 0); 1237554c0a3aSHans de Goede SetSeqNum(pwlanhdr, 0); 1238554c0a3aSHans de Goede 1239f2e741cbSHariprasad Kelam if (bQoS) { 1240554c0a3aSHans de Goede struct ieee80211_qos_hdr *pwlanqoshdr; 1241554c0a3aSHans de Goede 1242554c0a3aSHans de Goede SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); 1243554c0a3aSHans de Goede 1244554c0a3aSHans de Goede pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe; 1245554c0a3aSHans de Goede SetPriority(&pwlanqoshdr->qos_ctrl, AC); 1246554c0a3aSHans de Goede SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp); 1247554c0a3aSHans de Goede 1248554c0a3aSHans de Goede pktlen = sizeof(struct ieee80211_qos_hdr); 1249554c0a3aSHans de Goede } else { 1250554c0a3aSHans de Goede SetFrameSubType(pframe, WIFI_DATA_NULL); 1251554c0a3aSHans de Goede 1252554c0a3aSHans de Goede pktlen = sizeof(struct ieee80211_hdr_3addr); 1253554c0a3aSHans de Goede } 1254554c0a3aSHans de Goede 1255554c0a3aSHans de Goede *pLength = pktlen; 1256554c0a3aSHans de Goede } 1257554c0a3aSHans de Goede 1258554c0a3aSHans de Goede static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) 1259554c0a3aSHans de Goede { 1260554c0a3aSHans de Goede struct xmit_frame *pcmdframe; 1261554c0a3aSHans de Goede struct pkt_attrib *pattrib; 1262554c0a3aSHans de Goede struct xmit_priv *pxmitpriv; 1263554c0a3aSHans de Goede u32 BeaconLength = 0; 1264554c0a3aSHans de Goede u32 BTQosNullLength = 0; 1265554c0a3aSHans de Goede u8 *ReservedPagePacket; 1266554c0a3aSHans de Goede u8 TxDescLen, TxDescOffset; 1267554c0a3aSHans de Goede u8 TotalPageNum = 0, CurtPktPageNum = 0, RsvdPageNum = 0; 1268554c0a3aSHans de Goede u16 BufIndex, PageSize; 1269554c0a3aSHans de Goede u32 TotalPacketLen, MaxRsvdPageBufSize = 0; 1270*dc9a4304SMarco Cesati struct rsvdpage_loc RsvdPageLoc; 1271554c0a3aSHans de Goede 1272554c0a3aSHans de Goede 1273554c0a3aSHans de Goede /* DBG_8192C("+" FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); */ 1274554c0a3aSHans de Goede 1275554c0a3aSHans de Goede pxmitpriv = &padapter->xmitpriv; 1276554c0a3aSHans de Goede TxDescLen = TXDESC_SIZE; 1277554c0a3aSHans de Goede TxDescOffset = TXDESC_OFFSET; 1278554c0a3aSHans de Goede PageSize = PAGE_SIZE_TX_8723B; 1279554c0a3aSHans de Goede 1280554c0a3aSHans de Goede RsvdPageNum = BCNQ_PAGE_NUM_8723B; 1281554c0a3aSHans de Goede MaxRsvdPageBufSize = RsvdPageNum*PageSize; 1282554c0a3aSHans de Goede 1283554c0a3aSHans de Goede pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); 12847cd6f4b0SHimadri Pandya if (!pcmdframe) { 1285554c0a3aSHans de Goede DBG_8192C("%s: alloc ReservedPagePacket fail!\n", __func__); 1286554c0a3aSHans de Goede return; 1287554c0a3aSHans de Goede } 1288554c0a3aSHans de Goede 1289554c0a3aSHans de Goede ReservedPagePacket = pcmdframe->buf_addr; 1290*dc9a4304SMarco Cesati memset(&RsvdPageLoc, 0, sizeof(struct rsvdpage_loc)); 1291554c0a3aSHans de Goede 1292554c0a3aSHans de Goede /* 3 (1) beacon */ 1293554c0a3aSHans de Goede BufIndex = TxDescOffset; 1294554c0a3aSHans de Goede ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); 1295554c0a3aSHans de Goede 1296554c0a3aSHans de Goede /* When we count the first page size, we need to reserve description size for the RSVD */ 1297554c0a3aSHans de Goede /* packet, it will be filled in front of the packet in TXPKTBUF. */ 1298554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + BeaconLength); 1299554c0a3aSHans de Goede /* If we don't add 1 more page, the WOWLAN function has a problem. Baron thinks it's a bug of firmware */ 1300554c0a3aSHans de Goede if (CurtPktPageNum == 1) 1301554c0a3aSHans de Goede CurtPktPageNum += 1; 1302554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 1303554c0a3aSHans de Goede 1304554c0a3aSHans de Goede BufIndex += (CurtPktPageNum*PageSize); 1305554c0a3aSHans de Goede 1306554c0a3aSHans de Goede /* Jump to lastest page */ 1307554c0a3aSHans de Goede if (BufIndex < (MaxRsvdPageBufSize - PageSize)) { 1308554c0a3aSHans de Goede BufIndex = TxDescOffset + (MaxRsvdPageBufSize - PageSize); 1309554c0a3aSHans de Goede TotalPageNum = BCNQ_PAGE_NUM_8723B - 1; 1310554c0a3aSHans de Goede } 1311554c0a3aSHans de Goede 1312554c0a3aSHans de Goede /* 3 (6) BT Qos null data */ 1313554c0a3aSHans de Goede RsvdPageLoc.LocBTQosNull = TotalPageNum; 1314554c0a3aSHans de Goede ConstructBtNullFunctionData( 1315554c0a3aSHans de Goede padapter, 1316554c0a3aSHans de Goede &ReservedPagePacket[BufIndex], 1317554c0a3aSHans de Goede &BTQosNullLength, 1318554c0a3aSHans de Goede NULL, 1319554c0a3aSHans de Goede true, 0, 0, false 1320554c0a3aSHans de Goede ); 1321554c0a3aSHans de Goede rtl8723b_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true, false); 1322554c0a3aSHans de Goede 1323554c0a3aSHans de Goede CurtPktPageNum = (u8)PageNum_128(TxDescLen + BTQosNullLength); 1324554c0a3aSHans de Goede 1325554c0a3aSHans de Goede TotalPageNum += CurtPktPageNum; 1326554c0a3aSHans de Goede 1327554c0a3aSHans de Goede TotalPacketLen = BufIndex + BTQosNullLength; 1328554c0a3aSHans de Goede if (TotalPacketLen > MaxRsvdPageBufSize) { 1329554c0a3aSHans de Goede DBG_8192C(FUNC_ADPT_FMT ": ERROR: The rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", 1330554c0a3aSHans de Goede FUNC_ADPT_ARG(padapter), TotalPacketLen, MaxRsvdPageBufSize); 1331554c0a3aSHans de Goede goto error; 1332554c0a3aSHans de Goede } 1333554c0a3aSHans de Goede 1334554c0a3aSHans de Goede /* update attribute */ 1335554c0a3aSHans de Goede pattrib = &pcmdframe->attrib; 1336554c0a3aSHans de Goede update_mgntframe_attrib(padapter, pattrib); 1337554c0a3aSHans de Goede pattrib->qsel = 0x10; 1338554c0a3aSHans de Goede pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; 1339554c0a3aSHans de Goede dump_mgntframe_and_wait(padapter, pcmdframe, 100); 1340554c0a3aSHans de Goede 1341554c0a3aSHans de Goede /* DBG_8192C(FUNC_ADPT_FMT ": Set RSVD page location to Fw, TotalPacketLen(%d), TotalPageNum(%d)\n", */ 1342554c0a3aSHans de Goede /* FUNC_ADPT_ARG(padapter), TotalPacketLen, TotalPageNum); */ 1343554c0a3aSHans de Goede rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); 1344554c0a3aSHans de Goede rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); 1345554c0a3aSHans de Goede 1346554c0a3aSHans de Goede return; 1347554c0a3aSHans de Goede 1348554c0a3aSHans de Goede error: 1349554c0a3aSHans de Goede rtw_free_xmitframe(pxmitpriv, pcmdframe); 1350554c0a3aSHans de Goede } 1351554c0a3aSHans de Goede 1352554c0a3aSHans de Goede void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter) 1353554c0a3aSHans de Goede { 1354554c0a3aSHans de Goede struct hal_com_data *pHalData; 1355554c0a3aSHans de Goede struct mlme_ext_priv *pmlmeext; 1356554c0a3aSHans de Goede struct mlme_ext_info *pmlmeinfo; 1357554c0a3aSHans de Goede u8 bRecover = false; 1358554c0a3aSHans de Goede u8 bcn_valid = false; 1359554c0a3aSHans de Goede u8 DLBcnCount = 0; 1360554c0a3aSHans de Goede u32 poll = 0; 1361554c0a3aSHans de Goede u8 val8; 1362554c0a3aSHans de Goede 1363554c0a3aSHans de Goede 1364554c0a3aSHans de Goede DBG_8192C("+" FUNC_ADPT_FMT ": iface_type =%d fw_state = 0x%08X\n", 1365554c0a3aSHans de Goede FUNC_ADPT_ARG(padapter), get_iface_type(padapter), get_fwstate(&padapter->mlmepriv)); 1366554c0a3aSHans de Goede 1367f55a6d45SArnd Bergmann #ifdef DEBUG 1368554c0a3aSHans de Goede if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == false) { 1369554c0a3aSHans de Goede DBG_8192C(FUNC_ADPT_FMT ": [WARNING] not in AP mode!!\n", 1370554c0a3aSHans de Goede FUNC_ADPT_ARG(padapter)); 1371554c0a3aSHans de Goede } 1372f55a6d45SArnd Bergmann #endif /* DEBUG */ 1373554c0a3aSHans de Goede 1374554c0a3aSHans de Goede pHalData = GET_HAL_DATA(padapter); 1375554c0a3aSHans de Goede pmlmeext = &padapter->mlmeextpriv; 1376554c0a3aSHans de Goede pmlmeinfo = &pmlmeext->mlmext_info; 1377554c0a3aSHans de Goede 1378554c0a3aSHans de Goede /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ 1379554c0a3aSHans de Goede /* Suggested by filen. Added by tynli. */ 1380554c0a3aSHans de Goede rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); 1381554c0a3aSHans de Goede 1382554c0a3aSHans de Goede /* set REG_CR bit 8 */ 1383554c0a3aSHans de Goede val8 = rtw_read8(padapter, REG_CR+1); 1384554c0a3aSHans de Goede val8 |= BIT(0); /* ENSWBCN */ 1385554c0a3aSHans de Goede rtw_write8(padapter, REG_CR+1, val8); 1386554c0a3aSHans de Goede 1387554c0a3aSHans de Goede /* Disable Hw protection for a time which revserd for Hw sending beacon. */ 1388554c0a3aSHans de Goede /* Fix download reserved page packet fail that access collision with the protection time. */ 1389554c0a3aSHans de Goede /* 2010.05.11. Added by tynli. */ 1390554c0a3aSHans de Goede val8 = rtw_read8(padapter, REG_BCN_CTRL); 1391554c0a3aSHans de Goede val8 &= ~EN_BCN_FUNCTION; 1392554c0a3aSHans de Goede val8 |= DIS_TSF_UDT; 1393554c0a3aSHans de Goede rtw_write8(padapter, REG_BCN_CTRL, val8); 1394554c0a3aSHans de Goede 1395554c0a3aSHans de Goede /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ 1396554c0a3aSHans de Goede if (pHalData->RegFwHwTxQCtrl & BIT(6)) 1397554c0a3aSHans de Goede bRecover = true; 1398554c0a3aSHans de Goede 1399554c0a3aSHans de Goede /* To tell Hw the packet is not a real beacon frame. */ 1400554c0a3aSHans de Goede pHalData->RegFwHwTxQCtrl &= ~BIT(6); 1401554c0a3aSHans de Goede rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); 1402554c0a3aSHans de Goede 1403554c0a3aSHans de Goede /* Clear beacon valid check bit. */ 1404554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); 1405554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); 1406554c0a3aSHans de Goede 1407554c0a3aSHans de Goede DLBcnCount = 0; 1408554c0a3aSHans de Goede poll = 0; 1409554c0a3aSHans de Goede do { 1410554c0a3aSHans de Goede SetFwRsvdPagePkt_BTCoex(padapter); 1411554c0a3aSHans de Goede DLBcnCount++; 1412554c0a3aSHans de Goede do { 1413554c0a3aSHans de Goede yield(); 1414554c0a3aSHans de Goede /* mdelay(10); */ 1415554c0a3aSHans de Goede /* check rsvd page download OK. */ 1416554c0a3aSHans de Goede rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, &bcn_valid); 1417554c0a3aSHans de Goede poll++; 1418554c0a3aSHans de Goede } while (!bcn_valid && (poll%10) != 0 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 1419554c0a3aSHans de Goede } while (!bcn_valid && (DLBcnCount <= 100) && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); 1420554c0a3aSHans de Goede 1421f2e741cbSHariprasad Kelam if (bcn_valid) { 1422554c0a3aSHans de Goede struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); 1423554c0a3aSHans de Goede pwrctl->fw_psmode_iface_id = padapter->iface_id; 1424d0cc39cdSRoss Schmidt DBG_8192C("%s: DL RSVD page success! DLBcnCount:%d, poll:%d\n", 1425554c0a3aSHans de Goede ADPT_ARG(padapter), DLBcnCount, poll); 1426554c0a3aSHans de Goede } else { 1427d0cc39cdSRoss Schmidt DBG_8192C("%s: DL RSVD page fail! DLBcnCount:%d, poll:%d\n", 1428554c0a3aSHans de Goede ADPT_ARG(padapter), DLBcnCount, poll); 1429d0cc39cdSRoss Schmidt DBG_8192C("%s: DL RSVD page fail! bSurpriseRemoved =%d\n", 1430554c0a3aSHans de Goede ADPT_ARG(padapter), padapter->bSurpriseRemoved); 1431d0cc39cdSRoss Schmidt DBG_8192C("%s: DL RSVD page fail! bDriverStopped =%d\n", 1432554c0a3aSHans de Goede ADPT_ARG(padapter), padapter->bDriverStopped); 1433554c0a3aSHans de Goede } 1434554c0a3aSHans de Goede 1435554c0a3aSHans de Goede /* 2010.05.11. Added by tynli. */ 1436554c0a3aSHans de Goede val8 = rtw_read8(padapter, REG_BCN_CTRL); 1437554c0a3aSHans de Goede val8 |= EN_BCN_FUNCTION; 1438554c0a3aSHans de Goede val8 &= ~DIS_TSF_UDT; 1439554c0a3aSHans de Goede rtw_write8(padapter, REG_BCN_CTRL, val8); 1440554c0a3aSHans de Goede 1441554c0a3aSHans de Goede /* To make sure that if there exists an adapter which would like to send beacon. */ 1442554c0a3aSHans de Goede /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ 1443554c0a3aSHans de Goede /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ 1444554c0a3aSHans de Goede /* the beacon cannot be sent by HW. */ 1445554c0a3aSHans de Goede /* 2010.06.23. Added by tynli. */ 1446554c0a3aSHans de Goede if (bRecover) { 1447554c0a3aSHans de Goede pHalData->RegFwHwTxQCtrl |= BIT(6); 1448554c0a3aSHans de Goede rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); 1449554c0a3aSHans de Goede } 1450554c0a3aSHans de Goede 1451554c0a3aSHans de Goede /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ 1452554c0a3aSHans de Goede val8 = rtw_read8(padapter, REG_CR+1); 1453554c0a3aSHans de Goede val8 &= ~BIT(0); /* ~ENSWBCN */ 1454554c0a3aSHans de Goede rtw_write8(padapter, REG_CR+1, val8); 1455554c0a3aSHans de Goede } 1456