/****************************************************************************** * * Copyright(c) 2007 - 2017 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #define _HAL_COM_C_ #include #include "hal_com_h2c.h" #include "hal_data.h" #ifdef RTW_HALMAC #include "../../hal/hal_halmac.h" #endif void rtw_dump_fw_info(void *sel, _adapter *adapter) { HAL_DATA_TYPE *hal_data = NULL; if (!adapter) return; hal_data = GET_HAL_DATA(adapter); if (hal_data->bFWReady) RTW_PRINT_SEL(sel, "FW VER -%d.%d\n", hal_data->firmware_version, hal_data->firmware_sub_version); else RTW_PRINT_SEL(sel, "FW not ready\n"); } /* #define CONFIG_GTK_OL_DBG */ /*#define DBG_SEC_CAM_MOVE*/ #ifdef DBG_SEC_CAM_MOVE void rtw_hal_move_sta_gk_to_dk(_adapter *adapter) { struct mlme_priv *pmlmepriv = &adapter->mlmepriv; int cam_id, index = 0; u8 *addr = NULL; if (!MLME_IS_STA(adapter)) return; addr = get_bssid(pmlmepriv); if (addr == NULL) { RTW_INFO("%s: get bssid MAC addr fail!!\n", __func__); return; } rtw_clean_dk_section(adapter); do { cam_id = rtw_camid_search(adapter, addr, index, 1); if (cam_id == -1) RTW_INFO("%s: cam_id: %d, key_id:%d\n", __func__, cam_id, index); else rtw_sec_cam_swap(adapter, cam_id, index); index++; } while (index < 4); } void rtw_hal_read_sta_dk_key(_adapter *adapter, u8 key_id) { struct security_priv *psecuritypriv = &adapter->securitypriv; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; _irqL irqL; u8 get_key[16]; _rtw_memset(get_key, 0, sizeof(get_key)); if (key_id > 4) { RTW_INFO("%s [ERROR] gtk_keyindex:%d invalid\n", __func__, key_id); rtw_warn_on(1); return; } rtw_sec_read_cam_ent(adapter, key_id, NULL, NULL, get_key); /*update key into related sw variable*/ _enter_critical_bh(&cam_ctl->lock, &irqL); if (_rtw_camid_is_gk(adapter, key_id)) { RTW_INFO("[HW KEY] -Key-id:%d "KEY_FMT"\n", key_id, KEY_ARG(get_key)); RTW_INFO("[cam_cache KEY] - Key-id:%d "KEY_FMT"\n", key_id, KEY_ARG(&dvobj->cam_cache[key_id].key)); } _exit_critical_bh(&cam_ctl->lock, &irqL); } #endif #ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE char rtw_phy_para_file_path[PATH_LENGTH_MAX]; #endif void dump_chip_info(HAL_VERSION ChipVersion) { int cnt = 0; u8 buf[128] = {0}; if (IS_8188E(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188E_"); else if (IS_8188F(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188F_"); else if (IS_8812_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8812_"); else if (IS_8192E(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8192E_"); else if (IS_8821_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8821_"); else if (IS_8723B_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723B_"); else if (IS_8703B_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8703B_"); else if (IS_8723D_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723D_"); else if (IS_8814A_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8814A_"); else if (IS_8822B_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8822B_"); else if (IS_8821C_SERIES(ChipVersion)) cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8821C_"); else cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_UNKNOWN_"); cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(ChipVersion) ? "Normal_Chip" : "Test_Chip"); if (IS_CHIP_VENDOR_TSMC(ChipVersion)) cnt += sprintf((buf + cnt), "%s_", "TSMC"); else if (IS_CHIP_VENDOR_UMC(ChipVersion)) cnt += sprintf((buf + cnt), "%s_", "UMC"); else if (IS_CHIP_VENDOR_SMIC(ChipVersion)) cnt += sprintf((buf + cnt), "%s_", "SMIC"); if (IS_A_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "A_CUT_"); else if (IS_B_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "B_CUT_"); else if (IS_C_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "C_CUT_"); else if (IS_D_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "D_CUT_"); else if (IS_E_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "E_CUT_"); else if (IS_F_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "F_CUT_"); else if (IS_I_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "I_CUT_"); else if (IS_J_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "J_CUT_"); else if (IS_K_CUT(ChipVersion)) cnt += sprintf((buf + cnt), "K_CUT_"); else cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_", ChipVersion.CUTVersion); if (IS_1T1R(ChipVersion)) cnt += sprintf((buf + cnt), "1T1R_"); else if (IS_1T2R(ChipVersion)) cnt += sprintf((buf + cnt), "1T2R_"); else if (IS_2T2R(ChipVersion)) cnt += sprintf((buf + cnt), "2T2R_"); else if (IS_3T3R(ChipVersion)) cnt += sprintf((buf + cnt), "3T3R_"); else if (IS_3T4R(ChipVersion)) cnt += sprintf((buf + cnt), "3T4R_"); else if (IS_4T4R(ChipVersion)) cnt += sprintf((buf + cnt), "4T4R_"); else cnt += sprintf((buf + cnt), "UNKNOWN_RFTYPE(%d)_", ChipVersion.RFType); cnt += sprintf((buf + cnt), "RomVer(%d)\n", ChipVersion.ROMVer); RTW_INFO("%s", buf); } void rtw_hal_config_rftype(PADAPTER padapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); if (IS_1T1R(pHalData->version_id)) { pHalData->rf_type = RF_1T1R; pHalData->NumTotalRFPath = 1; } else if (IS_2T2R(pHalData->version_id)) { pHalData->rf_type = RF_2T2R; pHalData->NumTotalRFPath = 2; } else if (IS_1T2R(pHalData->version_id)) { pHalData->rf_type = RF_1T2R; pHalData->NumTotalRFPath = 2; } else if (IS_3T3R(pHalData->version_id)) { pHalData->rf_type = RF_3T3R; pHalData->NumTotalRFPath = 3; } else if (IS_4T4R(pHalData->version_id)) { pHalData->rf_type = RF_4T4R; pHalData->NumTotalRFPath = 4; } else { pHalData->rf_type = RF_1T1R; pHalData->NumTotalRFPath = 1; } RTW_INFO("%s RF_Type is %d TotalTxPath is %d\n", __FUNCTION__, pHalData->rf_type, pHalData->NumTotalRFPath); } #define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 /* * Description: * Use hardware(efuse), driver parameter(registry) and default channel plan * to decide which one should be used. * * Parameters: * padapter pointer of adapter * hw_alpha2 country code from HW (efuse/eeprom/mapfile) * hw_chplan channel plan from HW (efuse/eeprom/mapfile) * BIT[7] software configure mode; 0:Enable, 1:disable * BIT[6:0] Channel Plan * sw_alpha2 country code from HW (registry/module param) * sw_chplan channel plan from SW (registry/module param) * def_chplan channel plan used when HW/SW both invalid * AutoLoadFail efuse autoload fail or not * */ void hal_com_config_channel_plan( IN PADAPTER padapter, IN char *hw_alpha2, IN u8 hw_chplan, IN char *sw_alpha2, IN u8 sw_chplan, IN u8 def_chplan, IN BOOLEAN AutoLoadFail ) { struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter); PHAL_DATA_TYPE pHalData; u8 force_hw_chplan = _FALSE; int chplan = -1; const struct country_chplan *country_ent = NULL, *ent; pHalData = GET_HAL_DATA(padapter); /* treat 0xFF as invalid value, bypass hw_chplan & force_hw_chplan parsing */ if (hw_chplan == 0xFF) goto chk_hw_country_code; if (AutoLoadFail == _TRUE) goto chk_sw_config; #ifndef CONFIG_FORCE_SW_CHANNEL_PLAN if (hw_chplan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) force_hw_chplan = _TRUE; #endif hw_chplan &= (~EEPROM_CHANNEL_PLAN_BY_HW_MASK); chk_hw_country_code: if (hw_alpha2 && !IS_ALPHA2_NO_SPECIFIED(hw_alpha2)) { ent = rtw_get_chplan_from_country(hw_alpha2); if (ent) { /* get chplan from hw country code, by pass hw chplan setting */ country_ent = ent; chplan = ent->chplan; goto chk_sw_config; } else RTW_PRINT("%s unsupported hw_alpha2:\"%c%c\"\n", __func__, hw_alpha2[0], hw_alpha2[1]); } if (rtw_is_channel_plan_valid(hw_chplan)) chplan = hw_chplan; else if (force_hw_chplan == _TRUE) { RTW_PRINT("%s unsupported hw_chplan:0x%02X\n", __func__, hw_chplan); /* hw infomaton invalid, refer to sw information */ force_hw_chplan = _FALSE; } chk_sw_config: if (force_hw_chplan == _TRUE) goto done; if (sw_alpha2 && !IS_ALPHA2_NO_SPECIFIED(sw_alpha2)) { ent = rtw_get_chplan_from_country(sw_alpha2); if (ent) { /* get chplan from sw country code, by pass sw chplan setting */ country_ent = ent; chplan = ent->chplan; goto done; } else RTW_PRINT("%s unsupported sw_alpha2:\"%c%c\"\n", __func__, sw_alpha2[0], sw_alpha2[1]); } if (rtw_is_channel_plan_valid(sw_chplan)) { /* cancel hw_alpha2 because chplan is specified by sw_chplan*/ country_ent = NULL; chplan = sw_chplan; } else if (sw_chplan != RTW_CHPLAN_UNSPECIFIED) RTW_PRINT("%s unsupported sw_chplan:0x%02X\n", __func__, sw_chplan); done: if (chplan == -1) { RTW_PRINT("%s use def_chplan:0x%02X\n", __func__, def_chplan); chplan = def_chplan; } else if (country_ent) { RTW_PRINT("%s country code:\"%c%c\" with chplan:0x%02X\n", __func__ , country_ent->alpha2[0], country_ent->alpha2[1], country_ent->chplan); } else RTW_PRINT("%s chplan:0x%02X\n", __func__, chplan); rfctl->country_ent = country_ent; rfctl->ChannelPlan = chplan; pHalData->bDisableSWChannelPlan = force_hw_chplan; } BOOLEAN HAL_IsLegalChannel( IN PADAPTER Adapter, IN u32 Channel ) { BOOLEAN bLegalChannel = _TRUE; if (Channel > 14) { if (is_supported_5g(Adapter->registrypriv.wireless_mode) == _FALSE) { bLegalChannel = _FALSE; RTW_INFO("Channel > 14 but wireless_mode do not support 5G\n"); } } else if ((Channel <= 14) && (Channel >= 1)) { if (IsSupported24G(Adapter->registrypriv.wireless_mode) == _FALSE) { bLegalChannel = _FALSE; RTW_INFO("(Channel <= 14) && (Channel >=1) but wireless_mode do not support 2.4G\n"); } } else { bLegalChannel = _FALSE; RTW_INFO("Channel is Invalid !!!\n"); } return bLegalChannel; } u8 MRateToHwRate(u8 rate) { u8 ret = DESC_RATE1M; switch (rate) { case MGN_1M: ret = DESC_RATE1M; break; case MGN_2M: ret = DESC_RATE2M; break; case MGN_5_5M: ret = DESC_RATE5_5M; break; case MGN_11M: ret = DESC_RATE11M; break; case MGN_6M: ret = DESC_RATE6M; break; case MGN_9M: ret = DESC_RATE9M; break; case MGN_12M: ret = DESC_RATE12M; break; case MGN_18M: ret = DESC_RATE18M; break; case MGN_24M: ret = DESC_RATE24M; break; case MGN_36M: ret = DESC_RATE36M; break; case MGN_48M: ret = DESC_RATE48M; break; case MGN_54M: ret = DESC_RATE54M; break; case MGN_MCS0: ret = DESC_RATEMCS0; break; case MGN_MCS1: ret = DESC_RATEMCS1; break; case MGN_MCS2: ret = DESC_RATEMCS2; break; case MGN_MCS3: ret = DESC_RATEMCS3; break; case MGN_MCS4: ret = DESC_RATEMCS4; break; case MGN_MCS5: ret = DESC_RATEMCS5; break; case MGN_MCS6: ret = DESC_RATEMCS6; break; case MGN_MCS7: ret = DESC_RATEMCS7; break; case MGN_MCS8: ret = DESC_RATEMCS8; break; case MGN_MCS9: ret = DESC_RATEMCS9; break; case MGN_MCS10: ret = DESC_RATEMCS10; break; case MGN_MCS11: ret = DESC_RATEMCS11; break; case MGN_MCS12: ret = DESC_RATEMCS12; break; case MGN_MCS13: ret = DESC_RATEMCS13; break; case MGN_MCS14: ret = DESC_RATEMCS14; break; case MGN_MCS15: ret = DESC_RATEMCS15; break; case MGN_MCS16: ret = DESC_RATEMCS16; break; case MGN_MCS17: ret = DESC_RATEMCS17; break; case MGN_MCS18: ret = DESC_RATEMCS18; break; case MGN_MCS19: ret = DESC_RATEMCS19; break; case MGN_MCS20: ret = DESC_RATEMCS20; break; case MGN_MCS21: ret = DESC_RATEMCS21; break; case MGN_MCS22: ret = DESC_RATEMCS22; break; case MGN_MCS23: ret = DESC_RATEMCS23; break; case MGN_MCS24: ret = DESC_RATEMCS24; break; case MGN_MCS25: ret = DESC_RATEMCS25; break; case MGN_MCS26: ret = DESC_RATEMCS26; break; case MGN_MCS27: ret = DESC_RATEMCS27; break; case MGN_MCS28: ret = DESC_RATEMCS28; break; case MGN_MCS29: ret = DESC_RATEMCS29; break; case MGN_MCS30: ret = DESC_RATEMCS30; break; case MGN_MCS31: ret = DESC_RATEMCS31; break; case MGN_VHT1SS_MCS0: ret = DESC_RATEVHTSS1MCS0; break; case MGN_VHT1SS_MCS1: ret = DESC_RATEVHTSS1MCS1; break; case MGN_VHT1SS_MCS2: ret = DESC_RATEVHTSS1MCS2; break; case MGN_VHT1SS_MCS3: ret = DESC_RATEVHTSS1MCS3; break; case MGN_VHT1SS_MCS4: ret = DESC_RATEVHTSS1MCS4; break; case MGN_VHT1SS_MCS5: ret = DESC_RATEVHTSS1MCS5; break; case MGN_VHT1SS_MCS6: ret = DESC_RATEVHTSS1MCS6; break; case MGN_VHT1SS_MCS7: ret = DESC_RATEVHTSS1MCS7; break; case MGN_VHT1SS_MCS8: ret = DESC_RATEVHTSS1MCS8; break; case MGN_VHT1SS_MCS9: ret = DESC_RATEVHTSS1MCS9; break; case MGN_VHT2SS_MCS0: ret = DESC_RATEVHTSS2MCS0; break; case MGN_VHT2SS_MCS1: ret = DESC_RATEVHTSS2MCS1; break; case MGN_VHT2SS_MCS2: ret = DESC_RATEVHTSS2MCS2; break; case MGN_VHT2SS_MCS3: ret = DESC_RATEVHTSS2MCS3; break; case MGN_VHT2SS_MCS4: ret = DESC_RATEVHTSS2MCS4; break; case MGN_VHT2SS_MCS5: ret = DESC_RATEVHTSS2MCS5; break; case MGN_VHT2SS_MCS6: ret = DESC_RATEVHTSS2MCS6; break; case MGN_VHT2SS_MCS7: ret = DESC_RATEVHTSS2MCS7; break; case MGN_VHT2SS_MCS8: ret = DESC_RATEVHTSS2MCS8; break; case MGN_VHT2SS_MCS9: ret = DESC_RATEVHTSS2MCS9; break; case MGN_VHT3SS_MCS0: ret = DESC_RATEVHTSS3MCS0; break; case MGN_VHT3SS_MCS1: ret = DESC_RATEVHTSS3MCS1; break; case MGN_VHT3SS_MCS2: ret = DESC_RATEVHTSS3MCS2; break; case MGN_VHT3SS_MCS3: ret = DESC_RATEVHTSS3MCS3; break; case MGN_VHT3SS_MCS4: ret = DESC_RATEVHTSS3MCS4; break; case MGN_VHT3SS_MCS5: ret = DESC_RATEVHTSS3MCS5; break; case MGN_VHT3SS_MCS6: ret = DESC_RATEVHTSS3MCS6; break; case MGN_VHT3SS_MCS7: ret = DESC_RATEVHTSS3MCS7; break; case MGN_VHT3SS_MCS8: ret = DESC_RATEVHTSS3MCS8; break; case MGN_VHT3SS_MCS9: ret = DESC_RATEVHTSS3MCS9; break; case MGN_VHT4SS_MCS0: ret = DESC_RATEVHTSS4MCS0; break; case MGN_VHT4SS_MCS1: ret = DESC_RATEVHTSS4MCS1; break; case MGN_VHT4SS_MCS2: ret = DESC_RATEVHTSS4MCS2; break; case MGN_VHT4SS_MCS3: ret = DESC_RATEVHTSS4MCS3; break; case MGN_VHT4SS_MCS4: ret = DESC_RATEVHTSS4MCS4; break; case MGN_VHT4SS_MCS5: ret = DESC_RATEVHTSS4MCS5; break; case MGN_VHT4SS_MCS6: ret = DESC_RATEVHTSS4MCS6; break; case MGN_VHT4SS_MCS7: ret = DESC_RATEVHTSS4MCS7; break; case MGN_VHT4SS_MCS8: ret = DESC_RATEVHTSS4MCS8; break; case MGN_VHT4SS_MCS9: ret = DESC_RATEVHTSS4MCS9; break; default: break; } return ret; } u8 hw_rate_to_m_rate(u8 rate) { u8 ret_rate = MGN_1M; switch (rate) { case DESC_RATE1M: ret_rate = MGN_1M; break; case DESC_RATE2M: ret_rate = MGN_2M; break; case DESC_RATE5_5M: ret_rate = MGN_5_5M; break; case DESC_RATE11M: ret_rate = MGN_11M; break; case DESC_RATE6M: ret_rate = MGN_6M; break; case DESC_RATE9M: ret_rate = MGN_9M; break; case DESC_RATE12M: ret_rate = MGN_12M; break; case DESC_RATE18M: ret_rate = MGN_18M; break; case DESC_RATE24M: ret_rate = MGN_24M; break; case DESC_RATE36M: ret_rate = MGN_36M; break; case DESC_RATE48M: ret_rate = MGN_48M; break; case DESC_RATE54M: ret_rate = MGN_54M; break; case DESC_RATEMCS0: ret_rate = MGN_MCS0; break; case DESC_RATEMCS1: ret_rate = MGN_MCS1; break; case DESC_RATEMCS2: ret_rate = MGN_MCS2; break; case DESC_RATEMCS3: ret_rate = MGN_MCS3; break; case DESC_RATEMCS4: ret_rate = MGN_MCS4; break; case DESC_RATEMCS5: ret_rate = MGN_MCS5; break; case DESC_RATEMCS6: ret_rate = MGN_MCS6; break; case DESC_RATEMCS7: ret_rate = MGN_MCS7; break; case DESC_RATEMCS8: ret_rate = MGN_MCS8; break; case DESC_RATEMCS9: ret_rate = MGN_MCS9; break; case DESC_RATEMCS10: ret_rate = MGN_MCS10; break; case DESC_RATEMCS11: ret_rate = MGN_MCS11; break; case DESC_RATEMCS12: ret_rate = MGN_MCS12; break; case DESC_RATEMCS13: ret_rate = MGN_MCS13; break; case DESC_RATEMCS14: ret_rate = MGN_MCS14; break; case DESC_RATEMCS15: ret_rate = MGN_MCS15; break; case DESC_RATEMCS16: ret_rate = MGN_MCS16; break; case DESC_RATEMCS17: ret_rate = MGN_MCS17; break; case DESC_RATEMCS18: ret_rate = MGN_MCS18; break; case DESC_RATEMCS19: ret_rate = MGN_MCS19; break; case DESC_RATEMCS20: ret_rate = MGN_MCS20; break; case DESC_RATEMCS21: ret_rate = MGN_MCS21; break; case DESC_RATEMCS22: ret_rate = MGN_MCS22; break; case DESC_RATEMCS23: ret_rate = MGN_MCS23; break; case DESC_RATEMCS24: ret_rate = MGN_MCS24; break; case DESC_RATEMCS25: ret_rate = MGN_MCS25; break; case DESC_RATEMCS26: ret_rate = MGN_MCS26; break; case DESC_RATEMCS27: ret_rate = MGN_MCS27; break; case DESC_RATEMCS28: ret_rate = MGN_MCS28; break; case DESC_RATEMCS29: ret_rate = MGN_MCS29; break; case DESC_RATEMCS30: ret_rate = MGN_MCS30; break; case DESC_RATEMCS31: ret_rate = MGN_MCS31; break; case DESC_RATEVHTSS1MCS0: ret_rate = MGN_VHT1SS_MCS0; break; case DESC_RATEVHTSS1MCS1: ret_rate = MGN_VHT1SS_MCS1; break; case DESC_RATEVHTSS1MCS2: ret_rate = MGN_VHT1SS_MCS2; break; case DESC_RATEVHTSS1MCS3: ret_rate = MGN_VHT1SS_MCS3; break; case DESC_RATEVHTSS1MCS4: ret_rate = MGN_VHT1SS_MCS4; break; case DESC_RATEVHTSS1MCS5: ret_rate = MGN_VHT1SS_MCS5; break; case DESC_RATEVHTSS1MCS6: ret_rate = MGN_VHT1SS_MCS6; break; case DESC_RATEVHTSS1MCS7: ret_rate = MGN_VHT1SS_MCS7; break; case DESC_RATEVHTSS1MCS8: ret_rate = MGN_VHT1SS_MCS8; break; case DESC_RATEVHTSS1MCS9: ret_rate = MGN_VHT1SS_MCS9; break; case DESC_RATEVHTSS2MCS0: ret_rate = MGN_VHT2SS_MCS0; break; case DESC_RATEVHTSS2MCS1: ret_rate = MGN_VHT2SS_MCS1; break; case DESC_RATEVHTSS2MCS2: ret_rate = MGN_VHT2SS_MCS2; break; case DESC_RATEVHTSS2MCS3: ret_rate = MGN_VHT2SS_MCS3; break; case DESC_RATEVHTSS2MCS4: ret_rate = MGN_VHT2SS_MCS4; break; case DESC_RATEVHTSS2MCS5: ret_rate = MGN_VHT2SS_MCS5; break; case DESC_RATEVHTSS2MCS6: ret_rate = MGN_VHT2SS_MCS6; break; case DESC_RATEVHTSS2MCS7: ret_rate = MGN_VHT2SS_MCS7; break; case DESC_RATEVHTSS2MCS8: ret_rate = MGN_VHT2SS_MCS8; break; case DESC_RATEVHTSS2MCS9: ret_rate = MGN_VHT2SS_MCS9; break; case DESC_RATEVHTSS3MCS0: ret_rate = MGN_VHT3SS_MCS0; break; case DESC_RATEVHTSS3MCS1: ret_rate = MGN_VHT3SS_MCS1; break; case DESC_RATEVHTSS3MCS2: ret_rate = MGN_VHT3SS_MCS2; break; case DESC_RATEVHTSS3MCS3: ret_rate = MGN_VHT3SS_MCS3; break; case DESC_RATEVHTSS3MCS4: ret_rate = MGN_VHT3SS_MCS4; break; case DESC_RATEVHTSS3MCS5: ret_rate = MGN_VHT3SS_MCS5; break; case DESC_RATEVHTSS3MCS6: ret_rate = MGN_VHT3SS_MCS6; break; case DESC_RATEVHTSS3MCS7: ret_rate = MGN_VHT3SS_MCS7; break; case DESC_RATEVHTSS3MCS8: ret_rate = MGN_VHT3SS_MCS8; break; case DESC_RATEVHTSS3MCS9: ret_rate = MGN_VHT3SS_MCS9; break; case DESC_RATEVHTSS4MCS0: ret_rate = MGN_VHT4SS_MCS0; break; case DESC_RATEVHTSS4MCS1: ret_rate = MGN_VHT4SS_MCS1; break; case DESC_RATEVHTSS4MCS2: ret_rate = MGN_VHT4SS_MCS2; break; case DESC_RATEVHTSS4MCS3: ret_rate = MGN_VHT4SS_MCS3; break; case DESC_RATEVHTSS4MCS4: ret_rate = MGN_VHT4SS_MCS4; break; case DESC_RATEVHTSS4MCS5: ret_rate = MGN_VHT4SS_MCS5; break; case DESC_RATEVHTSS4MCS6: ret_rate = MGN_VHT4SS_MCS6; break; case DESC_RATEVHTSS4MCS7: ret_rate = MGN_VHT4SS_MCS7; break; case DESC_RATEVHTSS4MCS8: ret_rate = MGN_VHT4SS_MCS8; break; case DESC_RATEVHTSS4MCS9: ret_rate = MGN_VHT4SS_MCS9; break; default: RTW_INFO("hw_rate_to_m_rate(): Non supported Rate [%x]!!!\n", rate); break; } return ret_rate; } void HalSetBrateCfg( IN PADAPTER Adapter, IN u8 *mBratesOS, OUT u16 *pBrateCfg) { u8 i, is_brate, brate; for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { is_brate = mBratesOS[i] & IEEE80211_BASIC_RATE_MASK; brate = mBratesOS[i] & 0x7f; if (is_brate) { switch (brate) { case IEEE80211_CCK_RATE_1MB: *pBrateCfg |= RATE_1M; break; case IEEE80211_CCK_RATE_2MB: *pBrateCfg |= RATE_2M; break; case IEEE80211_CCK_RATE_5MB: *pBrateCfg |= RATE_5_5M; break; case IEEE80211_CCK_RATE_11MB: *pBrateCfg |= RATE_11M; break; case IEEE80211_OFDM_RATE_6MB: *pBrateCfg |= RATE_6M; break; case IEEE80211_OFDM_RATE_9MB: *pBrateCfg |= RATE_9M; break; case IEEE80211_OFDM_RATE_12MB: *pBrateCfg |= RATE_12M; break; case IEEE80211_OFDM_RATE_18MB: *pBrateCfg |= RATE_18M; break; case IEEE80211_OFDM_RATE_24MB: *pBrateCfg |= RATE_24M; break; case IEEE80211_OFDM_RATE_36MB: *pBrateCfg |= RATE_36M; break; case IEEE80211_OFDM_RATE_48MB: *pBrateCfg |= RATE_48M; break; case IEEE80211_OFDM_RATE_54MB: *pBrateCfg |= RATE_54M; break; } } } } static VOID _OneOutPipeMapping( IN PADAPTER pAdapter ) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ } static VOID _TwoOutPipeMapping( IN PADAPTER pAdapter, IN BOOLEAN bWIFICfg ) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); if (bWIFICfg) { /* WMM */ /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ /* { 0, 1, 0, 1, 0, 0, 0, 0, 0 }; */ /* 0:ep_0 num, 1:ep_1 num */ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ } else { /* typical setting */ /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ /* { 1, 1, 0, 0, 0, 0, 0, 0, 0 }; */ /* 0:ep_0 num, 1:ep_1 num */ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ } } static VOID _ThreeOutPipeMapping( IN PADAPTER pAdapter, IN BOOLEAN bWIFICfg ) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); if (bWIFICfg) { /* for WMM */ /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ /* { 1, 2, 1, 0, 0, 0, 0, 0, 0 }; */ /* 0:H, 1:N, 2:L */ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ } else { /* typical setting */ /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ /* { 2, 2, 1, 0, 0, 0, 0, 0, 0 }; */ /* 0:H, 1:N, 2:L */ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ } } static VOID _FourOutPipeMapping( IN PADAPTER pAdapter, IN BOOLEAN bWIFICfg ) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); if (bWIFICfg) { /* for WMM */ /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ /* { 1, 2, 1, 0, 0, 0, 0, 0, 0 }; */ /* 0:H, 1:N, 2:L ,3:E */ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[3];/* HIGH */ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ } else { /* typical setting */ /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ /* { 2, 2, 1, 0, 0, 0, 0, 0, 0 }; */ /* 0:H, 1:N, 2:L */ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[3];/* HIGH */ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ } } BOOLEAN Hal_MappingOutPipe( IN PADAPTER pAdapter, IN u8 NumOutPipe ) { struct registry_priv *pregistrypriv = &pAdapter->registrypriv; BOOLEAN bWIFICfg = (pregistrypriv->wifi_spec) ? _TRUE : _FALSE; BOOLEAN result = _TRUE; switch (NumOutPipe) { case 2: _TwoOutPipeMapping(pAdapter, bWIFICfg); break; case 3: case 4: _ThreeOutPipeMapping(pAdapter, bWIFICfg); break; case 1: _OneOutPipeMapping(pAdapter); break; default: result = _FALSE; break; } return result; } void rtw_hal_reqtxrpt(_adapter *padapter, u8 macid) { if (padapter->hal_func.reqtxrpt) padapter->hal_func.reqtxrpt(padapter, macid); } void rtw_hal_dump_macaddr(void *sel, _adapter *adapter) { int i; _adapter *iface; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); u8 mac_addr[ETH_ALEN]; #ifdef CONFIG_MI_WITH_MBSSID_CAM rtw_mbid_cam_dump(sel, __func__, adapter); #else for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->padapters[i]; if (iface) { rtw_hal_get_hwreg(iface, HW_VAR_MAC_ADDR, mac_addr); RTW_PRINT_SEL(sel, ADPT_FMT"- hw port(%d) mac_addr ="MAC_FMT"\n", ADPT_ARG(iface), iface->hw_port, MAC_ARG(mac_addr)); } } #endif } #ifdef RTW_HALMAC void rtw_hal_hw_port_enable(_adapter *adapter) { #if 1 u8 port_enable = _TRUE; rtw_hal_set_hwreg(adapter, HW_VAR_PORT_CFG, &port_enable); #else struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct rtw_halmac_bcn_ctrl bcn_ctrl; _rtw_memset(&bcn_ctrl, 0, sizeof(struct rtw_halmac_bcn_ctrl)); bcn_ctrl.enable_bcn = 1; bcn_ctrl.rx_bssid_fit = 1; bcn_ctrl.rxbcn_rpt = 1; /*rtw_halmac_get_bcn_ctrl(struct dvobj_priv *d, enum _hw_port hwport, struct rtw_halmac_bcn_ctrl *bcn_ctrl)*/ if (rtw_halmac_set_bcn_ctrl(dvobj, get_hw_port(adapter), &bcn_ctrl) == -1) { RTW_ERR(ADPT_FMT" - hw port(%d) enable fail!!\n", ADPT_ARG(adapter), get_hw_port(adapter)); rtw_warn_on(1); } #endif } void rtw_hal_hw_port_disable(_adapter *adapter) { u8 port_enable = _FALSE; rtw_hal_set_hwreg(adapter, HW_VAR_PORT_CFG, &port_enable); } void rtw_restore_hw_port_cfg(_adapter *adapter) { #ifdef CONFIG_MI_WITH_MBSSID_CAM #else int i; _adapter *iface; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->padapters[i]; if (iface) rtw_hal_hw_port_enable(iface); } #endif } #endif void rtw_restore_mac_addr(_adapter *adapter) { #ifdef CONFIG_MI_WITH_MBSSID_CAM rtw_mbid_cam_restore(adapter); #else int i; _adapter *iface; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->padapters[i]; if (iface) rtw_hal_set_hwreg(iface, HW_VAR_MAC_ADDR, adapter_mac_addr(iface)); } #endif if (1) rtw_hal_dump_macaddr(RTW_DBGDUMP, adapter); } void rtw_init_hal_com_default_value(PADAPTER Adapter) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); struct registry_priv *regsty = adapter_to_regsty(Adapter); pHalData->AntDetection = 1; pHalData->antenna_test = _FALSE; pHalData->RegIQKFWOffload = regsty->iqk_fw_offload; pHalData->ch_switch_offload = regsty->ch_switch_offload; } #ifdef CONFIG_FW_C2H_REG void c2h_evt_clear(_adapter *adapter) { rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); } s32 c2h_evt_read_88xx(_adapter *adapter, u8 *buf) { s32 ret = _FAIL; int i; u8 trigger; if (buf == NULL) goto exit; trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); if (trigger == C2H_EVT_HOST_CLOSE) { goto exit; /* Not ready */ } else if (trigger != C2H_EVT_FW_CLOSE) { goto clear_evt; /* Not a valid value */ } _rtw_memset(buf, 0, C2H_REG_LEN); /* Read ID, LEN, SEQ */ SET_C2H_ID_88XX(buf, rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL)); SET_C2H_SEQ_88XX(buf, rtw_read8(adapter, REG_C2HEVT_CMD_SEQ_88XX)); SET_C2H_PLEN_88XX(buf, rtw_read8(adapter, REG_C2HEVT_CMD_LEN_88XX)); if (0) { RTW_INFO("%s id=0x%02x, seq=%u, plen=%u, trigger=0x%02x\n", __func__ , C2H_ID_88XX(buf), C2H_SEQ_88XX(buf), C2H_PLEN_88XX(buf), trigger); } /* Read the content */ for (i = 0; i < C2H_PLEN_88XX(buf); i++) *(C2H_PAYLOAD_88XX(buf) + i) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i); RTW_DBG_DUMP("payload: ", C2H_PAYLOAD_88XX(buf), C2H_PLEN_88XX(buf)); ret = _SUCCESS; clear_evt: /* * Clear event to notify FW we have read the command. * If this field isn't clear, the FW won't update the next command message. */ c2h_evt_clear(adapter); exit: return ret; } #endif /* CONFIG_FW_C2H_REG */ #ifdef CONFIG_FW_C2H_PKT #ifndef DBG_C2H_PKT_PRE_HDL #define DBG_C2H_PKT_PRE_HDL 0 #endif #ifndef DBG_C2H_PKT_HDL #define DBG_C2H_PKT_HDL 0 #endif void rtw_hal_c2h_pkt_pre_hdl(_adapter *adapter, u8 *buf, u16 len) { #ifdef RTW_HALMAC /* TODO: extract hal_mac IC's code here*/ #else u8 parse_fail = 0; u8 hdl_here = 0; s32 ret = _FAIL; u8 id, seq, plen; u8 *payload; if (rtw_hal_c2h_pkt_hdr_parse(adapter, buf, len, &id, &seq, &plen, &payload) != _SUCCESS) { parse_fail = 1; goto exit; } hdl_here = rtw_hal_c2h_id_handle_directly(adapter, id, seq, plen, payload) == _TRUE ? 1 : 0; if (hdl_here) ret = rtw_hal_c2h_handler(adapter, id, seq, plen, payload); else ret = rtw_c2h_packet_wk_cmd(adapter, buf, len); exit: if (parse_fail) RTW_ERR("%s parse fail, buf=%p, len=:%u\n", __func__, buf, len); else if (ret != _SUCCESS || DBG_C2H_PKT_PRE_HDL > 0) { RTW_PRINT("%s: id=0x%02x, seq=%u, plen=%u, %s %s\n", __func__, id, seq, plen , hdl_here ? "handle" : "enqueue" , ret == _SUCCESS ? "ok" : "fail" ); if (DBG_C2H_PKT_PRE_HDL >= 2) RTW_PRINT_DUMP("dump: ", buf, len); } #endif } void rtw_hal_c2h_pkt_hdl(_adapter *adapter, u8 *buf, u16 len) { #ifdef RTW_HALMAC adapter->hal_func.hal_mac_c2h_handler(adapter, buf, len); #else u8 parse_fail = 0; u8 bypass = 0; s32 ret = _FAIL; u8 id, seq, plen; u8 *payload; if (rtw_hal_c2h_pkt_hdr_parse(adapter, buf, len, &id, &seq, &plen, &payload) != _SUCCESS) { parse_fail = 1; goto exit; } #ifdef CONFIG_WOWLAN if (adapter_to_pwrctl(adapter)->wowlan_mode == _TRUE) { bypass = 1; ret = _SUCCESS; goto exit; } #endif ret = rtw_hal_c2h_handler(adapter, id, seq, plen, payload); exit: if (parse_fail) RTW_ERR("%s parse fail, buf=%p, len=:%u\n", __func__, buf, len); else if (ret != _SUCCESS || bypass || DBG_C2H_PKT_HDL > 0) { RTW_PRINT("%s: id=0x%02x, seq=%u, plen=%u, %s %s\n", __func__, id, seq, plen , !bypass ? "handle" : "bypass" , ret == _SUCCESS ? "ok" : "fail" ); if (DBG_C2H_PKT_HDL >= 2) RTW_PRINT_DUMP("dump: ", buf, len); } #endif } #endif /* CONFIG_FW_C2H_PKT */ void c2h_iqk_offload(_adapter *adapter, u8 *data, u8 len) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); struct submit_ctx *iqk_sctx = &hal_data->iqk_sctx; RTW_INFO("IQK offload finish in %dms\n", rtw_get_passing_time_ms(iqk_sctx->submit_time)); if (0) RTW_INFO_DUMP("C2H_IQK_FINISH: ", data, len); rtw_sctx_done(&iqk_sctx); } int c2h_iqk_offload_wait(_adapter *adapter, u32 timeout_ms) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); struct submit_ctx *iqk_sctx = &hal_data->iqk_sctx; iqk_sctx->submit_time = rtw_get_current_time(); iqk_sctx->timeout_ms = timeout_ms; iqk_sctx->status = RTW_SCTX_SUBMITTED; return rtw_sctx_wait(iqk_sctx, __func__); } #define GET_C2H_MAC_HIDDEN_RPT_UUID_X(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 0, 0, 8) #define GET_C2H_MAC_HIDDEN_RPT_UUID_Y(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 1, 0, 8) #define GET_C2H_MAC_HIDDEN_RPT_UUID_Z(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 2, 0, 5) #define GET_C2H_MAC_HIDDEN_RPT_UUID_CRC(_data) LE_BITS_TO_2BYTE(((u8 *)(_data)) + 2, 5, 11) #define GET_C2H_MAC_HIDDEN_RPT_HCI_TYPE(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 4, 0, 4) #define GET_C2H_MAC_HIDDEN_RPT_PACKAGE_TYPE(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 4, 4, 3) #define GET_C2H_MAC_HIDDEN_RPT_TR_SWITCH(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 4, 7, 1) #define GET_C2H_MAC_HIDDEN_RPT_WL_FUNC(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 5, 0, 4) #define GET_C2H_MAC_HIDDEN_RPT_HW_STYPE(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 5, 4, 4) #define GET_C2H_MAC_HIDDEN_RPT_BW(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 6, 0, 3) #define GET_C2H_MAC_HIDDEN_RPT_ANT_NUM(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 6, 5, 3) #define GET_C2H_MAC_HIDDEN_RPT_80211_PROTOCOL(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 7, 2, 2) #define GET_C2H_MAC_HIDDEN_RPT_NIC_ROUTER(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 7, 6, 2) #ifndef DBG_C2H_MAC_HIDDEN_RPT_HANDLE #define DBG_C2H_MAC_HIDDEN_RPT_HANDLE 0 #endif #ifdef CONFIG_RTW_MAC_HIDDEN_RPT int c2h_mac_hidden_rpt_hdl(_adapter *adapter, u8 *data, u8 len) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); int ret = _FAIL; u32 uuid; u8 uuid_x; u8 uuid_y; u8 uuid_z; u16 uuid_crc; u8 hci_type; u8 package_type; u8 tr_switch; u8 wl_func; u8 hw_stype; u8 bw; u8 ant_num; u8 protocol; u8 nic; int i; if (len < MAC_HIDDEN_RPT_LEN) { RTW_WARN("%s len(%u) < %d\n", __func__, len, MAC_HIDDEN_RPT_LEN); goto exit; } uuid_x = GET_C2H_MAC_HIDDEN_RPT_UUID_X(data); uuid_y = GET_C2H_MAC_HIDDEN_RPT_UUID_Y(data); uuid_z = GET_C2H_MAC_HIDDEN_RPT_UUID_Z(data); uuid_crc = GET_C2H_MAC_HIDDEN_RPT_UUID_CRC(data); hci_type = GET_C2H_MAC_HIDDEN_RPT_HCI_TYPE(data); package_type = GET_C2H_MAC_HIDDEN_RPT_PACKAGE_TYPE(data); tr_switch = GET_C2H_MAC_HIDDEN_RPT_TR_SWITCH(data); wl_func = GET_C2H_MAC_HIDDEN_RPT_WL_FUNC(data); hw_stype = GET_C2H_MAC_HIDDEN_RPT_HW_STYPE(data); bw = GET_C2H_MAC_HIDDEN_RPT_BW(data); ant_num = GET_C2H_MAC_HIDDEN_RPT_ANT_NUM(data); protocol = GET_C2H_MAC_HIDDEN_RPT_80211_PROTOCOL(data); nic = GET_C2H_MAC_HIDDEN_RPT_NIC_ROUTER(data); if (DBG_C2H_MAC_HIDDEN_RPT_HANDLE) { for (i = 0; i < len; i++) RTW_PRINT("%s: 0x%02X\n", __func__, *(data + i)); RTW_PRINT("uuid x:0x%02x y:0x%02x z:0x%x crc:0x%x\n", uuid_x, uuid_y, uuid_z, uuid_crc); RTW_PRINT("hci_type:0x%x\n", hci_type); RTW_PRINT("package_type:0x%x\n", package_type); RTW_PRINT("tr_switch:0x%x\n", tr_switch); RTW_PRINT("wl_func:0x%x\n", wl_func); RTW_PRINT("hw_stype:0x%x\n", hw_stype); RTW_PRINT("bw:0x%x\n", bw); RTW_PRINT("ant_num:0x%x\n", ant_num); RTW_PRINT("protocol:0x%x\n", protocol); RTW_PRINT("nic:0x%x\n", nic); } /* * NOTICE: * for now, the following is common info/format * if there is any hal difference need to export * some IC dependent code will need to be implement */ hal_data->PackageType = package_type; hal_spec->wl_func &= mac_hidden_wl_func_to_hal_wl_func(wl_func); hal_spec->bw_cap &= mac_hidden_max_bw_to_hal_bw_cap(bw); hal_spec->tx_nss_num = rtw_min(hal_spec->tx_nss_num, ant_num); hal_spec->rx_nss_num = rtw_min(hal_spec->rx_nss_num, ant_num); hal_spec->proto_cap &= mac_hidden_proto_to_hal_proto_cap(protocol); hal_spec->hci_type = hci_type; /* TODO: tr_switch */ ret = _SUCCESS; exit: return ret; } int c2h_mac_hidden_rpt_2_hdl(_adapter *adapter, u8 *data, u8 len) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); int ret = _FAIL; int i; if (len < MAC_HIDDEN_RPT_2_LEN) { RTW_WARN("%s len(%u) < %d\n", __func__, len, MAC_HIDDEN_RPT_2_LEN); goto exit; } if (DBG_C2H_MAC_HIDDEN_RPT_HANDLE) { for (i = 0; i < len; i++) RTW_PRINT("%s: 0x%02X\n", __func__, *(data + i)); } #ifdef CONFIG_RTL8188F if (IS_8188F(hal_data->version_id)) { #define GET_C2H_MAC_HIDDEN_RPT_IRV(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 0, 0, 4) u8 irv = GET_C2H_MAC_HIDDEN_RPT_IRV(data); if (DBG_C2H_MAC_HIDDEN_RPT_HANDLE) RTW_PRINT("irv:0x%x\n", irv); if(irv != 0xf) hal_data->version_id.CUTVersion = irv; } #endif ret = _SUCCESS; exit: return ret; } int hal_read_mac_hidden_rpt(_adapter *adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); int ret = _FAIL; int ret_fwdl; u8 mac_hidden_rpt[MAC_HIDDEN_RPT_LEN + MAC_HIDDEN_RPT_2_LEN] = {0}; systime start = rtw_get_current_time(); u32 cnt = 0; u32 timeout_ms = 800; u32 min_cnt = 10; u8 id = C2H_DEFEATURE_RSVD; int i; #if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) u8 hci_type = rtw_get_intf_type(adapter); if ((hci_type == RTW_USB || hci_type == RTW_PCIE) && !rtw_is_hw_init_completed(adapter)) rtw_hal_power_on(adapter); #endif /* inform FW mac hidden rpt from reg is needed */ rtw_write8(adapter, REG_C2HEVT_MSG_NORMAL, C2H_DEFEATURE_RSVD); /* download FW */ pHalData->not_xmitframe_fw_dl = 1; ret_fwdl = rtw_hal_fw_dl(adapter, _FALSE); pHalData->not_xmitframe_fw_dl = 0; if (ret_fwdl != _SUCCESS) goto mac_hidden_rpt_hdl; /* polling for data ready */ start = rtw_get_current_time(); do { cnt++; id = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); if (id == C2H_MAC_HIDDEN_RPT || RTW_CANNOT_IO(adapter)) break; rtw_msleep_os(10); } while (rtw_get_passing_time_ms(start) < timeout_ms || cnt < min_cnt); if (id == C2H_MAC_HIDDEN_RPT) { /* read data */ for (i = 0; i < MAC_HIDDEN_RPT_LEN + MAC_HIDDEN_RPT_2_LEN; i++) mac_hidden_rpt[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i); } /* inform FW mac hidden rpt has read */ rtw_write8(adapter, REG_C2HEVT_MSG_NORMAL, C2H_DBG); mac_hidden_rpt_hdl: c2h_mac_hidden_rpt_hdl(adapter, mac_hidden_rpt, MAC_HIDDEN_RPT_LEN); c2h_mac_hidden_rpt_2_hdl(adapter, mac_hidden_rpt + MAC_HIDDEN_RPT_LEN, MAC_HIDDEN_RPT_2_LEN); if (ret_fwdl == _SUCCESS && id == C2H_MAC_HIDDEN_RPT) ret = _SUCCESS; exit: #if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) if ((hci_type == RTW_USB || hci_type == RTW_PCIE) && !rtw_is_hw_init_completed(adapter)) rtw_hal_power_off(adapter); #endif RTW_INFO("%s %s! (%u, %dms), fwdl:%d, id:0x%02x\n", __func__ , (ret == _SUCCESS) ? "OK" : "Fail", cnt, rtw_get_passing_time_ms(start), ret_fwdl, id); return ret; } #endif /* CONFIG_RTW_MAC_HIDDEN_RPT */ int c2h_defeature_dbg_hdl(_adapter *adapter, u8 *data, u8 len) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); int ret = _FAIL; int i; if (len < DEFEATURE_DBG_LEN) { RTW_WARN("%s len(%u) < %d\n", __func__, len, DEFEATURE_DBG_LEN); goto exit; } for (i = 0; i < len; i++) RTW_PRINT("%s: 0x%02X\n", __func__, *(data + i)); ret = _SUCCESS; exit: return ret; } #ifndef DBG_CUSTOMER_STR_RPT_HANDLE #define DBG_CUSTOMER_STR_RPT_HANDLE 0 #endif #ifdef CONFIG_RTW_CUSTOMER_STR s32 rtw_hal_h2c_customer_str_req(_adapter *adapter) { u8 h2c_data[H2C_CUSTOMER_STR_REQ_LEN] = {0}; SET_H2CCMD_CUSTOMER_STR_REQ_EN(h2c_data, 1); return rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_REQ, H2C_CUSTOMER_STR_REQ_LEN, h2c_data); } #define C2H_CUSTOMER_STR_RPT_BYTE0(_data) ((u8 *)(_data)) #define C2H_CUSTOMER_STR_RPT_2_BYTE8(_data) ((u8 *)(_data)) int c2h_customer_str_rpt_hdl(_adapter *adapter, u8 *data, u8 len) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); int ret = _FAIL; int i; if (len < CUSTOMER_STR_RPT_LEN) { RTW_WARN("%s len(%u) < %d\n", __func__, len, CUSTOMER_STR_RPT_LEN); goto exit; } if (DBG_CUSTOMER_STR_RPT_HANDLE) RTW_PRINT_DUMP("customer_str_rpt: ", data, CUSTOMER_STR_RPT_LEN); _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); if (dvobj->customer_str_sctx != NULL) { if (dvobj->customer_str_sctx->status != RTW_SCTX_SUBMITTED) RTW_WARN("%s invalid sctx.status:%d\n", __func__, dvobj->customer_str_sctx->status); _rtw_memcpy(dvobj->customer_str, C2H_CUSTOMER_STR_RPT_BYTE0(data), CUSTOMER_STR_RPT_LEN); dvobj->customer_str_sctx->status = RTX_SCTX_CSTR_WAIT_RPT2; } else RTW_WARN("%s sctx not set\n", __func__); _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); ret = _SUCCESS; exit: return ret; } int c2h_customer_str_rpt_2_hdl(_adapter *adapter, u8 *data, u8 len) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); int ret = _FAIL; int i; if (len < CUSTOMER_STR_RPT_2_LEN) { RTW_WARN("%s len(%u) < %d\n", __func__, len, CUSTOMER_STR_RPT_2_LEN); goto exit; } if (DBG_CUSTOMER_STR_RPT_HANDLE) RTW_PRINT_DUMP("customer_str_rpt_2: ", data, CUSTOMER_STR_RPT_2_LEN); _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); if (dvobj->customer_str_sctx != NULL) { if (dvobj->customer_str_sctx->status != RTX_SCTX_CSTR_WAIT_RPT2) RTW_WARN("%s rpt not ready\n", __func__); _rtw_memcpy(dvobj->customer_str + CUSTOMER_STR_RPT_LEN, C2H_CUSTOMER_STR_RPT_2_BYTE8(data), CUSTOMER_STR_RPT_2_LEN); rtw_sctx_done(&dvobj->customer_str_sctx); } else RTW_WARN("%s sctx not set\n", __func__); _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); ret = _SUCCESS; exit: return ret; } /* read customer str */ s32 rtw_hal_customer_str_read(_adapter *adapter, u8 *cs) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct submit_ctx sctx; s32 ret = _SUCCESS; _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); if (dvobj->customer_str_sctx != NULL) ret = _FAIL; else { rtw_sctx_init(&sctx, 2 * 1000); dvobj->customer_str_sctx = &sctx; } _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); if (ret == _FAIL) { RTW_WARN("%s another handle ongoing\n", __func__); goto exit; } ret = rtw_customer_str_req_cmd(adapter); if (ret != _SUCCESS) { RTW_WARN("%s read cmd fail\n", __func__); _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); dvobj->customer_str_sctx = NULL; _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); goto exit; } /* wait till rpt done or timeout */ rtw_sctx_wait(&sctx, __func__); _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); dvobj->customer_str_sctx = NULL; if (sctx.status == RTW_SCTX_DONE_SUCCESS) _rtw_memcpy(cs, dvobj->customer_str, RTW_CUSTOMER_STR_LEN); else ret = _FAIL; _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); exit: return ret; } s32 rtw_hal_h2c_customer_str_write(_adapter *adapter, const u8 *cs) { u8 h2c_data_w1[H2C_CUSTOMER_STR_W1_LEN] = {0}; u8 h2c_data_w2[H2C_CUSTOMER_STR_W2_LEN] = {0}; u8 h2c_data_w3[H2C_CUSTOMER_STR_W3_LEN] = {0}; s32 ret; SET_H2CCMD_CUSTOMER_STR_W1_EN(h2c_data_w1, 1); _rtw_memcpy(H2CCMD_CUSTOMER_STR_W1_BYTE0(h2c_data_w1), cs, 6); SET_H2CCMD_CUSTOMER_STR_W2_EN(h2c_data_w2, 1); _rtw_memcpy(H2CCMD_CUSTOMER_STR_W2_BYTE6(h2c_data_w2), cs + 6, 6); SET_H2CCMD_CUSTOMER_STR_W3_EN(h2c_data_w3, 1); _rtw_memcpy(H2CCMD_CUSTOMER_STR_W3_BYTE12(h2c_data_w3), cs + 6 + 6, 4); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_W1, H2C_CUSTOMER_STR_W1_LEN, h2c_data_w1); if (ret != _SUCCESS) { RTW_WARN("%s w1 fail\n", __func__); goto exit; } ret = rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_W2, H2C_CUSTOMER_STR_W2_LEN, h2c_data_w2); if (ret != _SUCCESS) { RTW_WARN("%s w2 fail\n", __func__); goto exit; } ret = rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_W3, H2C_CUSTOMER_STR_W3_LEN, h2c_data_w3); if (ret != _SUCCESS) { RTW_WARN("%s w3 fail\n", __func__); goto exit; } exit: return ret; } /* write customer str and check if value reported is the same as requested */ s32 rtw_hal_customer_str_write(_adapter *adapter, const u8 *cs) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct submit_ctx sctx; s32 ret = _SUCCESS; _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); if (dvobj->customer_str_sctx != NULL) ret = _FAIL; else { rtw_sctx_init(&sctx, 2 * 1000); dvobj->customer_str_sctx = &sctx; } _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); if (ret == _FAIL) { RTW_WARN("%s another handle ongoing\n", __func__); goto exit; } ret = rtw_customer_str_write_cmd(adapter, cs); if (ret != _SUCCESS) { RTW_WARN("%s write cmd fail\n", __func__); _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); dvobj->customer_str_sctx = NULL; _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); goto exit; } ret = rtw_customer_str_req_cmd(adapter); if (ret != _SUCCESS) { RTW_WARN("%s read cmd fail\n", __func__); _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); dvobj->customer_str_sctx = NULL; _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); goto exit; } /* wait till rpt done or timeout */ rtw_sctx_wait(&sctx, __func__); _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); dvobj->customer_str_sctx = NULL; if (sctx.status == RTW_SCTX_DONE_SUCCESS) { if (_rtw_memcmp(cs, dvobj->customer_str, RTW_CUSTOMER_STR_LEN) != _TRUE) { RTW_WARN("%s read back check fail\n", __func__); RTW_INFO_DUMP("write req: ", cs, RTW_CUSTOMER_STR_LEN); RTW_INFO_DUMP("read back: ", dvobj->customer_str, RTW_CUSTOMER_STR_LEN); ret = _FAIL; } } else ret = _FAIL; _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); exit: return ret; } #endif /* CONFIG_RTW_CUSTOMER_STR */ #ifdef RTW_PER_CMD_SUPPORT_FW #define H2C_REQ_PER_RPT_LEN 5 #define SET_H2CCMD_REQ_PER_RPT_GROUP_MACID(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 4, __Value) #define SET_H2CCMD_REQ_PER_RPT_RPT_TYPE(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE(__pH2CCmd, 4, 4, __Value) #define SET_H2CCMD_REQ_PER_RPT_MACID_BMAP(__pH2CCmd, __Value) SET_BITS_TO_LE_4BYTE(__pH2CCmd + 1, 0, 32, __Value) u8 rtw_hal_set_req_per_rpt_cmd(_adapter *adapter, u8 group_macid, u8 rpt_type, u32 macid_bitmap) { u8 ret = _FAIL; u8 cmd_buf[H2C_REQ_PER_RPT_LEN] = {0}; SET_H2CCMD_REQ_PER_RPT_GROUP_MACID(cmd_buf, group_macid); SET_H2CCMD_REQ_PER_RPT_RPT_TYPE(cmd_buf, rpt_type); SET_H2CCMD_REQ_PER_RPT_MACID_BMAP(cmd_buf, macid_bitmap); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_REQ_PER_RPT, H2C_REQ_PER_RPT_LEN, cmd_buf); return ret; } #define GET_C2H_PER_RATE_RPT_TYPE0_MACID0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)), 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE0_PER0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 1, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE0_RATE0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 2, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE0_BW0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 3, 0, 2) #define GET_C2H_PER_RATE_RPT_TYPE0_TOTAL_PKT0(_data) LE_BITS_TO_2BYTE(((u8 *)(_data)) + 4, 0, 16) #define GET_C2H_PER_RATE_RPT_TYPE0_MACID1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 6, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE0_PER1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 7, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE0_RATE1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 8, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE0_BW1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 9, 0, 2) #define GET_C2H_PER_RATE_RPT_TYPE0_TOTAL_PKT1(_data) LE_BITS_TO_2BYTE(((u8 *)(_data)) + 10, 0, 16) #define GET_C2H_PER_RATE_RPT_TYPE1_MACID0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)), 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_PER0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 1, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_RATE0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 2, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_BW0(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 3, 0, 2) #define GET_C2H_PER_RATE_RPT_TYPE1_MACID1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 4, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_PER1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 5, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_RATE1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 6, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_BW1(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 7, 0, 2) #define GET_C2H_PER_RATE_RPT_TYPE1_MACID2(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 8, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_PER2(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 9, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_RATE2(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 10, 0, 8) #define GET_C2H_PER_RATE_RPT_TYPE1_BW2(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 11, 0, 2) static void per_rate_rpt_update(_adapter *adapter, u8 mac_id, u8 per, u8 rate, u8 bw, u8 total_pkt) { #ifdef CONFIG_RTW_MESH rtw_ieee80211s_update_metric(adapter, mac_id, per, rate, bw, total_pkt); #endif } int c2h_per_rate_rpt_hdl(_adapter *adapter, u8 *data, u8 len) { /* Now only consider type0, since it covers all params in type1 * type0: mac_id, per, rate, bw, total_pkt * type1: mac_id, per, rate, bw */ u8 mac_id[2] = {0}, per[2] = {0}, rate[2] = {0}, bw[2] = {0}; u16 total_pkt[2] = {0}; int ret = _FAIL, i, macid_cnt = 0; /* type0: * 1 macid includes 6 bytes info + 1 byte 0xff * 2 macid includes 2*6 bytes info */ if (!(len == 7 || len == 12)) { RTW_WARN("%s len(%u) != 7 or 12\n", __FUNCTION__, len); goto exit; } macid_cnt++; mac_id[0] = GET_C2H_PER_RATE_RPT_TYPE0_MACID0(data); per[0] = GET_C2H_PER_RATE_RPT_TYPE0_PER0(data); rate[0] = GET_C2H_PER_RATE_RPT_TYPE0_RATE0(data); bw[0] = GET_C2H_PER_RATE_RPT_TYPE0_BW0(data); total_pkt[0] = GET_C2H_PER_RATE_RPT_TYPE0_TOTAL_PKT0(data); mac_id[1] = GET_C2H_PER_RATE_RPT_TYPE0_MACID1(data); /* 0xff means no report anymore */ if (mac_id[1] == 0xff) goto update_per; if (len != 12) { RTW_WARN("%s incorrect format\n", __FUNCTION__); goto exit; } macid_cnt++; per[1] = GET_C2H_PER_RATE_RPT_TYPE0_PER1(data); rate[1] = GET_C2H_PER_RATE_RPT_TYPE0_RATE1(data); bw[1] = GET_C2H_PER_RATE_RPT_TYPE0_BW1(data); total_pkt[1] = GET_C2H_PER_RATE_RPT_TYPE0_TOTAL_PKT1(data); update_per: for (i = 0; i < macid_cnt; i++) { RTW_DBG("[%s] type0 rpt[%d]: macid = %u, per = %u, " "rate = %u, bw = %u, total_pkt = %u\n", __FUNCTION__, i, mac_id[i], per[i], rate[i], bw[i], total_pkt[i]); per_rate_rpt_update(adapter, mac_id[i], per[i], rate[i], bw[i], total_pkt[i]); } ret = _SUCCESS; exit: return ret; } #endif /* RTW_PER_CMD_SUPPORT_FW */ void rtw_hal_update_sta_wset(_adapter *adapter, struct sta_info *psta) { u8 w_set = 0; if (psta->wireless_mode & WIRELESS_11B) w_set |= WIRELESS_CCK; if ((psta->wireless_mode & WIRELESS_11G) || (psta->wireless_mode & WIRELESS_11A)) w_set |= WIRELESS_OFDM; if (psta->wireless_mode & WIRELESS_11_24N) w_set |= WIRELESS_HT; if ((psta->wireless_mode & WIRELESS_11AC) || (psta->wireless_mode & WIRELESS_11_5N)) w_set |= WIRELESS_VHT; psta->cmn.support_wireless_set = w_set; } void rtw_hal_update_sta_mimo_type(_adapter *adapter, struct sta_info *psta) { s8 tx_nss, rx_nss; tx_nss = rtw_get_sta_tx_nss(adapter, psta); rx_nss = rtw_get_sta_rx_nss(adapter, psta); if ((tx_nss == 1) && (rx_nss == 1)) psta->cmn.mimo_type = RF_1T1R; else if ((tx_nss == 1) && (rx_nss == 2)) psta->cmn.mimo_type = RF_1T2R; else if ((tx_nss == 2) && (rx_nss == 2)) psta->cmn.mimo_type = RF_2T2R; else if ((tx_nss == 2) && (rx_nss == 3)) psta->cmn.mimo_type = RF_2T3R; else if ((tx_nss == 2) && (rx_nss == 4)) psta->cmn.mimo_type = RF_2T4R; else if ((tx_nss == 3) && (rx_nss == 3)) psta->cmn.mimo_type = RF_3T3R; else if ((tx_nss == 3) && (rx_nss == 4)) psta->cmn.mimo_type = RF_3T4R; else if ((tx_nss == 4) && (rx_nss == 4)) psta->cmn.mimo_type = RF_4T4R; else rtw_warn_on(1); RTW_INFO("STA - MAC_ID:%d, Tx - %d SS, Rx - %d SS\n", psta->cmn.mac_id, tx_nss, rx_nss); } void rtw_hal_update_sta_smps_cap(_adapter *adapter, struct sta_info *psta) { /*Spatial Multiplexing Power Save*/ #if 0 if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _TRUE) { #ifdef CONFIG_80211N_HT if (psta->htpriv.ht_option) { if (psta->htpriv.smps_cap == 0) psta->cmn.sm_ps = SM_PS_STATIC; else if (psta->htpriv.smps_cap == 1) psta->cmn.sm_ps = SM_PS_DYNAMIC; else psta->cmn.sm_ps = SM_PS_DISABLE; } #endif /* CONFIG_80211N_HT */ } else #endif psta->cmn.sm_ps = SM_PS_DISABLE; RTW_INFO("STA - MAC_ID:%d, SM_PS %d\n", psta->cmn.mac_id, psta->cmn.sm_ps); } u8 rtw_get_mgntframe_raid(_adapter *adapter, unsigned char network_type) { u8 raid; if (IS_NEW_GENERATION_IC(adapter)) { raid = (network_type & WIRELESS_11B) ? RATEID_IDX_B : RATEID_IDX_G; } else { raid = (network_type & WIRELESS_11B) ? RATR_INX_WIRELESS_B : RATR_INX_WIRELESS_G; } return raid; } void rtw_hal_update_sta_rate_mask(PADAPTER padapter, struct sta_info *psta) { struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); u8 i, rf_type, tx_nss; u64 tx_ra_bitmap = 0; if (psta == NULL) return; /* b/g mode ra_bitmap */ for (i = 0; i < sizeof(psta->bssrateset); i++) { if (psta->bssrateset[i]) tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i] & 0x7f); } #ifdef CONFIG_80211N_HT rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); #ifdef CONFIG_80211AC_VHT if (psta->vhtpriv.vht_option) { /* AC mode ra_bitmap */ tx_ra_bitmap |= (rtw_vht_mcs_map_to_bitmap(psta->vhtpriv.vht_mcs_map, tx_nss) << 12); } else #endif /* CONFIG_80211AC_VHT */ if (psta->htpriv.ht_option) { /* n mode ra_bitmap */ /* Handling SMPS mode for AP MODE only*/ if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) { /*0:static SMPS, 1:dynamic SMPS, 3:SMPS disabled, 2:reserved*/ if (psta->htpriv.smps_cap == 0 || psta->htpriv.smps_cap == 1) { /*operate with only one active receive chain // 11n-MCS rate <= MSC7*/ tx_nss = rtw_min(tx_nss, 1); } } tx_ra_bitmap |= (rtw_ht_mcs_set_to_bitmap(psta->htpriv.ht_cap.supp_mcs_set, tx_nss) << 12); } #endif /* CONFIG_80211N_HT */ psta->cmn.ra_info.ramask = tx_ra_bitmap; psta->init_rate = get_highest_rate_idx(tx_ra_bitmap) & 0x3f; } void rtw_hal_update_sta_ra_info(PADAPTER padapter, struct sta_info *psta) { rtw_hal_update_sta_mimo_type(padapter, psta); rtw_hal_update_sta_smps_cap(padapter, psta); rtw_hal_update_sta_rate_mask(padapter, psta); } #ifndef SEC_CAM_ACCESS_TIMEOUT_MS #define SEC_CAM_ACCESS_TIMEOUT_MS 200 #endif #ifndef DBG_SEC_CAM_ACCESS #define DBG_SEC_CAM_ACCESS 0 #endif u32 rtw_sec_read_cam(_adapter *adapter, u8 addr) { _mutex *mutex = &adapter_to_dvobj(adapter)->cam_ctl.sec_cam_access_mutex; u32 rdata; u32 cnt = 0; systime start = 0, end = 0; u8 timeout = 0; u8 sr = 0; _enter_critical_mutex(mutex, NULL); rtw_write32(adapter, REG_CAMCMD, CAM_POLLINIG | addr); start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(adapter)) { sr = 1; break; } cnt++; if (0 == (rtw_read32(adapter, REG_CAMCMD) & CAM_POLLINIG)) break; if (rtw_get_passing_time_ms(start) > SEC_CAM_ACCESS_TIMEOUT_MS) { timeout = 1; break; } } end = rtw_get_current_time(); rdata = rtw_read32(adapter, REG_CAMREAD); _exit_critical_mutex(mutex, NULL); if (DBG_SEC_CAM_ACCESS || timeout) { RTW_INFO(FUNC_ADPT_FMT" addr:0x%02x, rdata:0x%08x, to:%u, polling:%u, %d ms\n" , FUNC_ADPT_ARG(adapter), addr, rdata, timeout, cnt, rtw_get_time_interval_ms(start, end)); } return rdata; } void rtw_sec_write_cam(_adapter *adapter, u8 addr, u32 wdata) { _mutex *mutex = &adapter_to_dvobj(adapter)->cam_ctl.sec_cam_access_mutex; u32 cnt = 0; systime start = 0, end = 0; u8 timeout = 0; u8 sr = 0; _enter_critical_mutex(mutex, NULL); rtw_write32(adapter, REG_CAMWRITE, wdata); rtw_write32(adapter, REG_CAMCMD, CAM_POLLINIG | CAM_WRITE | addr); start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(adapter)) { sr = 1; break; } cnt++; if (0 == (rtw_read32(adapter, REG_CAMCMD) & CAM_POLLINIG)) break; if (rtw_get_passing_time_ms(start) > SEC_CAM_ACCESS_TIMEOUT_MS) { timeout = 1; break; } } end = rtw_get_current_time(); _exit_critical_mutex(mutex, NULL); if (DBG_SEC_CAM_ACCESS || timeout) { RTW_INFO(FUNC_ADPT_FMT" addr:0x%02x, wdata:0x%08x, to:%u, polling:%u, %d ms\n" , FUNC_ADPT_ARG(adapter), addr, wdata, timeout, cnt, rtw_get_time_interval_ms(start, end)); } } void rtw_sec_read_cam_ent(_adapter *adapter, u8 id, u8 *ctrl, u8 *mac, u8 *key) { unsigned int val, addr; u8 i; u32 rdata; u8 begin = 0; u8 end = 5; /* TODO: consider other key length accordingly */ if (!ctrl && !mac && !key) { rtw_warn_on(1); goto exit; } /* TODO: check id range */ if (!ctrl && !mac) begin = 2; /* read from key */ if (!key && !mac) end = 0; /* read to ctrl */ else if (!key) end = 2; /* read to mac */ for (i = begin; i <= end; i++) { rdata = rtw_sec_read_cam(adapter, (id << 3) | i); switch (i) { case 0: if (ctrl) _rtw_memcpy(ctrl, (u8 *)(&rdata), 2); if (mac) _rtw_memcpy(mac, ((u8 *)(&rdata)) + 2, 2); break; case 1: if (mac) _rtw_memcpy(mac + 2, (u8 *)(&rdata), 4); break; default: if (key) _rtw_memcpy(key + (i - 2) * 4, (u8 *)(&rdata), 4); break; } } exit: return; } void rtw_sec_write_cam_ent(_adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) { unsigned int i; int j; u8 addr; u32 wdata; /* TODO: consider other key length accordingly */ #if 0 switch ((ctrl & 0x1c) >> 2) { case _WEP40_: case _TKIP_: case _AES_: case _WEP104_: } #else j = 7; #endif for (; j >= 0; j--) { switch (j) { case 0: wdata = (ctrl | (mac[0] << 16) | (mac[1] << 24)); break; case 1: wdata = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); break; case 6: case 7: wdata = 0; break; default: i = (j - 2) << 2; wdata = (key[i] | (key[i + 1] << 8) | (key[i + 2] << 16) | (key[i + 3] << 24)); break; } addr = (id << 3) + j; rtw_sec_write_cam(adapter, addr, wdata); } } void rtw_sec_clr_cam_ent(_adapter *adapter, u8 id) { u8 addr; addr = (id << 3); rtw_sec_write_cam(adapter, addr, 0); } bool rtw_sec_read_cam_is_gk(_adapter *adapter, u8 id) { bool res; u16 ctrl; rtw_sec_read_cam_ent(adapter, id, (u8 *)&ctrl, NULL, NULL); res = (ctrl & BIT6) ? _TRUE : _FALSE; return res; } #ifdef CONFIG_MBSSID_CAM void rtw_mbid_cam_init(struct dvobj_priv *dvobj) { struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; _rtw_spinlock_init(&mbid_cam_ctl->lock); mbid_cam_ctl->bitmap = 0; ATOMIC_SET(&mbid_cam_ctl->mbid_entry_num, 0); _rtw_memset(&dvobj->mbid_cam_cache, 0, sizeof(dvobj->mbid_cam_cache)); } void rtw_mbid_cam_deinit(struct dvobj_priv *dvobj) { struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; _rtw_spinlock_free(&mbid_cam_ctl->lock); } void rtw_mbid_cam_reset(_adapter *adapter) { _irqL irqL; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); mbid_cam_ctl->bitmap = 0; _rtw_memset(&dvobj->mbid_cam_cache, 0, sizeof(dvobj->mbid_cam_cache)); _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); ATOMIC_SET(&mbid_cam_ctl->mbid_entry_num, 0); } static u8 _rtw_mbid_cam_search_by_macaddr(_adapter *adapter, u8 *mac_addr) { u8 i; u8 cam_id = INVALID_CAM_ID; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { if (mac_addr && _rtw_memcmp(dvobj->mbid_cam_cache[i].mac_addr, mac_addr, ETH_ALEN) == _TRUE) { cam_id = i; break; } } RTW_INFO("%s mac:"MAC_FMT" - cam_id:%d\n", __func__, MAC_ARG(mac_addr), cam_id); return cam_id; } u8 rtw_mbid_cam_search_by_macaddr(_adapter *adapter, u8 *mac_addr) { _irqL irqL; u8 cam_id = INVALID_CAM_ID; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); cam_id = _rtw_mbid_cam_search_by_macaddr(adapter, mac_addr); _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); return cam_id; } static u8 _rtw_mbid_cam_search_by_ifaceid(_adapter *adapter, u8 iface_id) { u8 i; u8 cam_id = INVALID_CAM_ID; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { if (iface_id == dvobj->mbid_cam_cache[i].iface_id) { cam_id = i; break; } } if (cam_id != INVALID_CAM_ID) RTW_INFO("%s iface_id:%d mac:"MAC_FMT" - cam_id:%d\n", __func__, iface_id, MAC_ARG(dvobj->mbid_cam_cache[cam_id].mac_addr), cam_id); return cam_id; } u8 rtw_mbid_cam_search_by_ifaceid(_adapter *adapter, u8 iface_id) { _irqL irqL; u8 cam_id = INVALID_CAM_ID; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); cam_id = _rtw_mbid_cam_search_by_ifaceid(adapter, iface_id); _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); return cam_id; } u8 rtw_get_max_mbid_cam_id(_adapter *adapter) { _irqL irqL; s8 i; u8 cam_id = INVALID_CAM_ID; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); for (i = (TOTAL_MBID_CAM_NUM - 1); i >= 0; i--) { if (mbid_cam_ctl->bitmap & BIT(i)) { cam_id = i; break; } } _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); /*RTW_INFO("%s max cam_id:%d\n", __func__, cam_id);*/ return cam_id; } inline u8 rtw_get_mbid_cam_entry_num(_adapter *adapter) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; return ATOMIC_READ(&mbid_cam_ctl->mbid_entry_num); } static inline void mbid_cam_cache_init(_adapter *adapter, struct mbid_cam_cache *pmbid_cam, u8 *mac_addr) { if (adapter && pmbid_cam && mac_addr) { _rtw_memcpy(pmbid_cam->mac_addr, mac_addr, ETH_ALEN); pmbid_cam->iface_id = adapter->iface_id; } } static inline void mbid_cam_cache_clr(struct mbid_cam_cache *pmbid_cam) { if (pmbid_cam) { _rtw_memset(pmbid_cam->mac_addr, 0, ETH_ALEN); pmbid_cam->iface_id = CONFIG_IFACE_NUMBER; } } u8 rtw_mbid_camid_alloc(_adapter *adapter, u8 *mac_addr) { _irqL irqL; u8 cam_id = INVALID_CAM_ID, i; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; u8 entry_num = ATOMIC_READ(&mbid_cam_ctl->mbid_entry_num); if (entry_num >= TOTAL_MBID_CAM_NUM) { RTW_INFO(FUNC_ADPT_FMT" failed !! MBSSID number :%d over TOTAL_CAM_ENTRY(8)\n", FUNC_ADPT_ARG(adapter), entry_num); rtw_warn_on(1); } if (INVALID_CAM_ID != rtw_mbid_cam_search_by_macaddr(adapter, mac_addr)) goto exit; _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { if (!(mbid_cam_ctl->bitmap & BIT(i))) { mbid_cam_ctl->bitmap |= BIT(i); cam_id = i; break; } } if ((cam_id != INVALID_CAM_ID) && (mac_addr)) mbid_cam_cache_init(adapter, &dvobj->mbid_cam_cache[cam_id], mac_addr); _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); if (cam_id != INVALID_CAM_ID) { ATOMIC_INC(&mbid_cam_ctl->mbid_entry_num); RTW_INFO("%s mac:"MAC_FMT" - cam_id:%d\n", __func__, MAC_ARG(mac_addr), cam_id); #ifdef DBG_MBID_CAM_DUMP rtw_mbid_cam_cache_dump(RTW_DBGDUMP, __func__, adapter); #endif } else RTW_INFO("%s [WARN] "MAC_FMT" - invalid cam_id:%d\n", __func__, MAC_ARG(mac_addr), cam_id); exit: return cam_id; } u8 rtw_mbid_cam_info_change(_adapter *adapter, u8 *mac_addr) { _irqL irqL; u8 entry_id = INVALID_CAM_ID; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); entry_id = _rtw_mbid_cam_search_by_ifaceid(adapter, adapter->iface_id); if (entry_id != INVALID_CAM_ID) mbid_cam_cache_init(adapter, &dvobj->mbid_cam_cache[entry_id], mac_addr); _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); return entry_id; } u8 rtw_mbid_cam_assign(_adapter *adapter, u8 *mac_addr, u8 camid) { _irqL irqL; u8 ret = _FALSE; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; if ((camid >= TOTAL_MBID_CAM_NUM) || (camid == INVALID_CAM_ID)) { RTW_INFO(FUNC_ADPT_FMT" failed !! invlaid mbid_canid :%d\n", FUNC_ADPT_ARG(adapter), camid); rtw_warn_on(1); } if (INVALID_CAM_ID != rtw_mbid_cam_search_by_macaddr(adapter, mac_addr)) goto exit; _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); if (!(mbid_cam_ctl->bitmap & BIT(camid))) { if (mac_addr) { mbid_cam_ctl->bitmap |= BIT(camid); mbid_cam_cache_init(adapter, &dvobj->mbid_cam_cache[camid], mac_addr); ret = _TRUE; } } _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); if (ret == _TRUE) { ATOMIC_INC(&mbid_cam_ctl->mbid_entry_num); RTW_INFO("%s mac:"MAC_FMT" - cam_id:%d\n", __func__, MAC_ARG(mac_addr), camid); #ifdef DBG_MBID_CAM_DUMP rtw_mbid_cam_cache_dump(RTW_DBGDUMP, __func__, adapter); #endif } else RTW_INFO("%s [WARN] mac:"MAC_FMT" - cam_id:%d assigned failed\n", __func__, MAC_ARG(mac_addr), camid); exit: return ret; } void rtw_mbid_camid_clean(_adapter *adapter, u8 mbss_canid) { _irqL irqL; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; if ((mbss_canid >= TOTAL_MBID_CAM_NUM) || (mbss_canid == INVALID_CAM_ID)) { RTW_INFO(FUNC_ADPT_FMT" failed !! invlaid mbid_canid :%d\n", FUNC_ADPT_ARG(adapter), mbss_canid); rtw_warn_on(1); } _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); mbid_cam_cache_clr(&dvobj->mbid_cam_cache[mbss_canid]); mbid_cam_ctl->bitmap &= (~BIT(mbss_canid)); _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); ATOMIC_DEC(&mbid_cam_ctl->mbid_entry_num); RTW_INFO("%s - cam_id:%d\n", __func__, mbss_canid); } int rtw_mbid_cam_cache_dump(void *sel, const char *fun_name, _adapter *adapter) { _irqL irqL; u8 i; _adapter *iface; u8 iface_id; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; u8 entry_num = ATOMIC_READ(&mbid_cam_ctl->mbid_entry_num); u8 max_cam_id = rtw_get_max_mbid_cam_id(adapter); RTW_PRINT_SEL(sel, "== MBSSID CAM DUMP (%s)==\n", fun_name); _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); RTW_PRINT_SEL(sel, "Entry numbers:%d, max_camid:%d, bitmap:0x%08x\n", entry_num, max_cam_id, mbid_cam_ctl->bitmap); for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { RTW_PRINT_SEL(sel, "CAM_ID = %d\t", i); if (mbid_cam_ctl->bitmap & BIT(i)) { iface_id = dvobj->mbid_cam_cache[i].iface_id; RTW_PRINT_SEL(sel, "IF_ID:%d\t", iface_id); RTW_PRINT_SEL(sel, "MAC Addr:"MAC_FMT"\t", MAC_ARG(dvobj->mbid_cam_cache[i].mac_addr)); iface = dvobj->padapters[iface_id]; if (iface) { if (MLME_IS_STA(iface)) RTW_PRINT_SEL(sel, "ROLE:%s\n", "STA"); else if (MLME_IS_AP(iface)) RTW_PRINT_SEL(sel, "ROLE:%s\n", "AP"); else if (MLME_IS_MESH(iface)) RTW_PRINT_SEL(sel, "ROLE:%s\n", "MESH"); else RTW_PRINT_SEL(sel, "ROLE:%s\n", "NONE"); } } else RTW_PRINT_SEL(sel, "N/A\n"); } _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); return 0; } static void read_mbssid_cam(_adapter *padapter, u8 cam_addr, u8 *mac) { u8 poll = 1; u8 cam_ready = _FALSE; u32 cam_data1 = 0; u16 cam_data2 = 0; if (RTW_CANNOT_RUN(padapter)) return; rtw_write32(padapter, REG_MBIDCAMCFG_2, BIT_MBIDCAM_POLL | ((cam_addr & MBIDCAM_ADDR_MASK) << MBIDCAM_ADDR_SHIFT)); do { if (0 == (rtw_read32(padapter, REG_MBIDCAMCFG_2) & BIT_MBIDCAM_POLL)) { cam_ready = _TRUE; break; } poll++; } while ((poll % 10) != 0 && !RTW_CANNOT_RUN(padapter)); if (cam_ready) { cam_data1 = rtw_read32(padapter, REG_MBIDCAMCFG_1); mac[0] = cam_data1 & 0xFF; mac[1] = (cam_data1 >> 8) & 0xFF; mac[2] = (cam_data1 >> 16) & 0xFF; mac[3] = (cam_data1 >> 24) & 0xFF; cam_data2 = rtw_read16(padapter, REG_MBIDCAMCFG_2); mac[4] = cam_data2 & 0xFF; mac[5] = (cam_data2 >> 8) & 0xFF; } } int rtw_mbid_cam_dump(void *sel, const char *fun_name, _adapter *adapter) { /*_irqL irqL;*/ u8 i; u8 mac_addr[ETH_ALEN]; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; RTW_PRINT_SEL(sel, "\n== MBSSID HW-CAM DUMP (%s)==\n", fun_name); /*_enter_critical_bh(&mbid_cam_ctl->lock, &irqL);*/ for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { RTW_PRINT_SEL(sel, "CAM_ID = %d\t", i); _rtw_memset(mac_addr, 0, ETH_ALEN); read_mbssid_cam(adapter, i, mac_addr); RTW_PRINT_SEL(sel, "MAC Addr:"MAC_FMT"\n", MAC_ARG(mac_addr)); } /*_exit_critical_bh(&mbid_cam_ctl->lock, &irqL);*/ return 0; } static void write_mbssid_cam(_adapter *padapter, u8 cam_addr, u8 *mac) { u32 cam_val[2] = {0}; cam_val[0] = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; cam_val[1] = ((cam_addr & MBIDCAM_ADDR_MASK) << MBIDCAM_ADDR_SHIFT) | (mac[5] << 8) | mac[4]; rtw_hal_set_hwreg(padapter, HW_VAR_MBSSID_CAM_WRITE, (u8 *)cam_val); } static void clear_mbssid_cam(_adapter *padapter, u8 cam_addr) { rtw_hal_set_hwreg(padapter, HW_VAR_MBSSID_CAM_CLEAR, &cam_addr); } static void enable_mbssid_cam(_adapter *adapter) { u8 max_cam_id = rtw_get_max_mbid_cam_id(adapter); /*enable MBSSID*/ rtw_hal_rcr_add(adapter, RCR_ENMBID); if (max_cam_id != INVALID_CAM_ID) { rtw_write8(adapter, REG_MBID_NUM, ((rtw_read8(adapter, REG_MBID_NUM) & 0xF8) | ((max_cam_id -1) & 0x07))); } } void rtw_mbid_cam_restore(_adapter *adapter) { u8 i; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; #ifdef DBG_MBID_CAM_DUMP rtw_mbid_cam_cache_dump(RTW_DBGDUMP, __func__, adapter); #endif for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { if (mbid_cam_ctl->bitmap & BIT(i)) { write_mbssid_cam(adapter, i, dvobj->mbid_cam_cache[i].mac_addr); RTW_INFO("%s - cam_id:%d => mac:"MAC_FMT"\n", __func__, i, MAC_ARG(dvobj->mbid_cam_cache[i].mac_addr)); } } enable_mbssid_cam(adapter); } #endif /*CONFIG_MBSSID_CAM*/ #ifdef CONFIG_MI_WITH_MBSSID_CAM void rtw_hal_set_macaddr_mbid(_adapter *adapter, u8 *mac_addr) { #if 0 /*TODO - modify for more flexible*/ u8 idx = 0; if ((check_fwstate(&adapter->mlmepriv, WIFI_STATION_STATE) == _TRUE) && (DEV_STA_NUM(adapter_to_dvobj(adapter)) == 1)) { for (idx = 0; idx < 6; idx++) rtw_write8(GET_PRIMARY_ADAPTER(adapter), (REG_MACID + idx), val[idx]); } else { /*MBID entry_id = 0~7 ,0 for root AP, 1~7 for VAP*/ u8 entry_id; if ((check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _TRUE) && (DEV_AP_NUM(adapter_to_dvobj(adapter)) == 1)) { entry_id = 0; if (rtw_mbid_cam_assign(adapter, val, entry_id)) { RTW_INFO(FUNC_ADPT_FMT" Root AP assigned success\n", FUNC_ADPT_ARG(adapter)); write_mbssid_cam(adapter, entry_id, val); } } else { entry_id = rtw_mbid_camid_alloc(adapter, val); if (entry_id != INVALID_CAM_ID) write_mbssid_cam(adapter, entry_id, val); } } #else { /* MBID entry_id = 0~7 ,for IFACE_ID0 ~ IFACE_IDx */ u8 entry_id = rtw_mbid_camid_alloc(adapter, mac_addr); if (entry_id != INVALID_CAM_ID) { write_mbssid_cam(adapter, entry_id, mac_addr); enable_mbssid_cam(adapter); } } #endif } void rtw_hal_change_macaddr_mbid(_adapter *adapter, u8 *mac_addr) { u8 idx = 0; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); u8 entry_id; if (!mac_addr) { rtw_warn_on(1); return; } entry_id = rtw_mbid_cam_info_change(adapter, mac_addr); if (entry_id != INVALID_CAM_ID) write_mbssid_cam(adapter, entry_id, mac_addr); } #ifdef CONFIG_SWTIMER_BASED_TXBCN u16 rtw_hal_bcn_interval_adjust(_adapter *adapter, u16 bcn_interval) { if (adapter_to_dvobj(adapter)->inter_bcn_space != bcn_interval) return adapter_to_dvobj(adapter)->inter_bcn_space; else return bcn_interval; } #endif/*CONFIG_SWTIMER_BASED_TXBCN*/ #endif/*#ifdef CONFIG_MI_WITH_MBSSID_CAM*/ static void rtw_hal_set_macaddr_port(_adapter *adapter, u8 *val) { u8 idx = 0; u32 reg_macid = 0; if (val == NULL) return; RTW_INFO("%s "ADPT_FMT"- hw port(%d) mac_addr ="MAC_FMT"\n", __func__, ADPT_ARG(adapter), adapter->hw_port, MAC_ARG(val)); #ifdef RTW_HALMAC rtw_halmac_set_mac_address(adapter_to_dvobj(adapter), adapter->hw_port, val); #else /* !RTW_HALMAC */ switch (adapter->hw_port) { case HW_PORT0: default: reg_macid = REG_MACID; break; case HW_PORT1: reg_macid = REG_MACID1; break; #if defined(CONFIG_RTL8814A) case HW_PORT2: reg_macid = REG_MACID2; break; case HW_PORT3: reg_macid = REG_MACID3; break; case HW_PORT4: reg_macid = REG_MACID4; break; #endif/*defined(CONFIG_RTL8814A)*/ } for (idx = 0; idx < 6; idx++) rtw_write8(GET_PRIMARY_ADAPTER(adapter), (reg_macid + idx), val[idx]); #endif /* !RTW_HALMAC */ } static void rtw_hal_get_macaddr_port(_adapter *adapter, u8 *mac_addr) { u8 idx = 0; u32 reg_macid = 0; if (mac_addr == NULL) return; _rtw_memset(mac_addr, 0, ETH_ALEN); #ifdef RTW_HALMAC rtw_halmac_get_mac_address(adapter_to_dvobj(adapter), adapter->hw_port, mac_addr); #else /* !RTW_HALMAC */ switch (adapter->hw_port) { case HW_PORT0: default: reg_macid = REG_MACID; break; case HW_PORT1: reg_macid = REG_MACID1; break; #if defined(CONFIG_RTL8814A) case HW_PORT2: reg_macid = REG_MACID2; break; case HW_PORT3: reg_macid = REG_MACID3; break; case HW_PORT4: reg_macid = REG_MACID4; break; #endif /*defined(CONFIG_RTL8814A)*/ } for (idx = 0; idx < 6; idx++) mac_addr[idx] = rtw_read8(GET_PRIMARY_ADAPTER(adapter), (reg_macid + idx)); #endif /* !RTW_HALMAC */ RTW_INFO("%s "ADPT_FMT"- hw port(%d) mac_addr ="MAC_FMT"\n", __func__, ADPT_ARG(adapter), adapter->hw_port, MAC_ARG(mac_addr)); } static void rtw_hal_set_bssid(_adapter *adapter, u8 *val) { #ifdef RTW_HALMAC rtw_halmac_set_bssid(adapter_to_dvobj(adapter), adapter->hw_port, val); #else /* !RTW_HALMAC */ u8 idx = 0; u32 reg_bssid = 0; switch (adapter->hw_port) { case HW_PORT0: default: reg_bssid = REG_BSSID; break; case HW_PORT1: reg_bssid = REG_BSSID1; break; #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) case HW_PORT2: reg_bssid = REG_BSSID2; break; case HW_PORT3: reg_bssid = REG_BSSID3; break; case HW_PORT4: reg_bssid = REG_BSSID4; break; #endif/*defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B)*/ } for (idx = 0 ; idx < 6; idx++) rtw_write8(adapter, (reg_bssid + idx), val[idx]); #endif /* !RTW_HALMAC */ RTW_INFO("%s "ADPT_FMT"- hw port -%d BSSID: "MAC_FMT"\n", __func__, ADPT_ARG(adapter), adapter->hw_port, MAC_ARG(val)); } static inline u8 hw_var_rcr_config(_adapter *adapter, u32 rcr) { int err; err = rtw_write32(adapter, REG_RCR, rcr); if (err == _SUCCESS) GET_HAL_DATA(adapter)->ReceiveConfig = rcr; return err; } static inline u8 hw_var_rcr_get(_adapter *adapter, u32 *rcr) { u32 v32; v32 = rtw_read32(adapter, REG_RCR); if (rcr) *rcr = v32; GET_HAL_DATA(adapter)->ReceiveConfig = v32; return _SUCCESS; } /* only check SW RCR variable */ inline u8 rtw_hal_rcr_check(_adapter *adapter, u32 check_bit) { PHAL_DATA_TYPE hal; u32 rcr; hal = GET_HAL_DATA(adapter); rcr = hal->ReceiveConfig; if ((rcr & check_bit) == check_bit) return 1; return 0; } inline u8 rtw_hal_rcr_add(_adapter *adapter, u32 add) { PHAL_DATA_TYPE hal; u32 rcr; u8 ret = _SUCCESS; hal = GET_HAL_DATA(adapter); rtw_hal_get_hwreg(adapter, HW_VAR_RCR, (u8 *)&rcr); rcr |= add; if (rcr != hal->ReceiveConfig) ret = rtw_hal_set_hwreg(adapter, HW_VAR_RCR, (u8 *)&rcr); return ret; } inline u8 rtw_hal_rcr_clear(_adapter *adapter, u32 clear) { PHAL_DATA_TYPE hal; u32 rcr; u8 ret = _SUCCESS; hal = GET_HAL_DATA(adapter); rtw_hal_get_hwreg(adapter, HW_VAR_RCR, (u8 *)&rcr); rcr &= ~clear; if (rcr != hal->ReceiveConfig) ret = rtw_hal_set_hwreg(adapter, HW_VAR_RCR, (u8 *)&rcr); return ret; } void rtw_hal_rcr_set_chk_bssid(_adapter *adapter, u8 self_action) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); u32 rcr, rcr_new; struct mi_state mstate, mstate_s; rtw_hal_get_hwreg(adapter, HW_VAR_RCR, (u8 *)&rcr); rcr_new = rcr; #ifdef CONFIG_MI_WITH_MBSSID_CAM rcr_new &= ~(RCR_CBSSID_BCN | RCR_CBSSID_DATA); #else rtw_mi_status_no_self(adapter, &mstate); rtw_mi_status_no_others(adapter, &mstate_s); /* only adjust parameters interested */ switch (self_action) { case MLME_SCAN_ENTER: mstate_s.scan_num = 1; mstate_s.scan_enter_num = 1; break; case MLME_SCAN_DONE: mstate_s.scan_enter_num = 0; break; #ifdef CONFIG_TDLS case MLME_TDLS_LINKED: mstate_s.ld_tdls_num = 1; break; case MLME_TDLS_NOLINK: mstate_s.ld_tdls_num = 0; break; #endif #ifdef CONFIG_AP_MODE case MLME_AP_STARTED: mstate_s.ap_num = 1; break; case MLME_AP_STOPPED: mstate_s.ap_num = 0; mstate_s.ld_ap_num = 0; break; #endif #ifdef CONFIG_RTW_MESH case MLME_MESH_STARTED: mstate_s.mesh_num = 1; break; case MLME_MESH_STOPPED: mstate_s.mesh_num = 0; mstate_s.ld_mesh_num = 0; break; #endif case MLME_ACTION_NONE: case MLME_STA_CONNECTING: case MLME_ADHOC_STARTED: /* caller without effect of decision */ break; default: rtw_warn_on(1); }; rtw_mi_status_merge(&mstate, &mstate_s); if (MSTATE_AP_NUM(&mstate) || MSTATE_MESH_NUM(&mstate) || MSTATE_TDLS_LD_NUM(&mstate) #ifdef CONFIG_FIND_BEST_CHANNEL || MSTATE_SCAN_ENTER_NUM(&mstate) #endif || hal_data->in_cta_test ) rcr_new &= ~RCR_CBSSID_DATA; else rcr_new |= RCR_CBSSID_DATA; if ((MSTATE_AP_NUM(&mstate) && adapter->registrypriv.wifi_spec) /* for 11n Logo 4.2.31/4.2.32 */ || MSTATE_MESH_NUM(&mstate) || MSTATE_SCAN_ENTER_NUM(&mstate) || hal_data->in_cta_test ) rcr_new &= ~RCR_CBSSID_BCN; else rcr_new |= RCR_CBSSID_BCN; #endif /* CONFIG_MI_WITH_MBSSID_CAM */ if (rcr != rcr_new) rtw_hal_set_hwreg(adapter, HW_VAR_RCR, (u8 *)&rcr_new); } static void hw_var_set_rcr_am(_adapter *adapter, u8 enable) { u32 rcr = RCR_AM; if (enable) rtw_hal_rcr_add(adapter, rcr); else rtw_hal_rcr_clear(adapter, rcr); } static void rtw_hal_get_msr(_adapter *adapter, u8 *net_type) { #ifdef RTW_HALMAC rtw_halmac_get_network_type(adapter_to_dvobj(adapter), adapter->hw_port, net_type); #else /* !RTW_HALMAC */ switch (adapter->hw_port) { case HW_PORT0: /*REG_CR - BIT[17:16]-Network Type for port 1*/ *net_type = rtw_read8(adapter, MSR) & 0x03; break; case HW_PORT1: /*REG_CR - BIT[19:18]-Network Type for port 1*/ *net_type = (rtw_read8(adapter, MSR) & 0x0C) >> 2; break; #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) case HW_PORT2: /*REG_CR_EXT- BIT[1:0]-Network Type for port 2*/ *net_type = rtw_read8(adapter, MSR1) & 0x03; break; case HW_PORT3: /*REG_CR_EXT- BIT[3:2]-Network Type for port 3*/ *net_type = (rtw_read8(adapter, MSR1) & 0x0C) >> 2; break; case HW_PORT4: /*REG_CR_EXT- BIT[5:4]-Network Type for port 4*/ *net_type = (rtw_read8(adapter, MSR1) & 0x30) >> 4; break; #endif /*#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B)*/ default: RTW_INFO("[WARN] "ADPT_FMT"- invalid hw port -%d\n", ADPT_ARG(adapter), adapter->hw_port); rtw_warn_on(1); break; } #endif /* !RTW_HALMAC */ } #if defined(CONFIG_MI_WITH_MBSSID_CAM) && defined(CONFIG_MBSSID_CAM) /*For 2 hw ports - 88E/92E/8812/8821/8723B*/ static u8 rtw_hal_net_type_decision(_adapter *adapter, u8 net_type) { if ((adapter->hw_port == HW_PORT0) && (rtw_get_mbid_cam_entry_num(adapter))) { if (net_type != _HW_STATE_NOLINK_) return _HW_STATE_AP_; } return net_type; } #endif static void rtw_hal_set_msr(_adapter *adapter, u8 net_type) { #ifdef RTW_HALMAC #if defined(CONFIG_MI_WITH_MBSSID_CAM) && defined(CONFIG_MBSSID_CAM) net_type = rtw_hal_net_type_decision(adapter, net_type); #endif rtw_halmac_set_network_type(adapter_to_dvobj(adapter), adapter->hw_port, net_type); #else /* !RTW_HALMAC */ u8 val8 = 0; switch (adapter->hw_port) { case HW_PORT0: #if defined(CONFIG_MI_WITH_MBSSID_CAM) && defined(CONFIG_MBSSID_CAM) net_type = rtw_hal_net_type_decision(adapter, net_type); #endif /*REG_CR - BIT[17:16]-Network Type for port 0*/ val8 = rtw_read8(adapter, MSR) & 0x0C; val8 |= net_type; rtw_write8(adapter, MSR, val8); break; case HW_PORT1: /*REG_CR - BIT[19:18]-Network Type for port 1*/ val8 = rtw_read8(adapter, MSR) & 0x03; val8 |= net_type << 2; rtw_write8(adapter, MSR, val8); break; #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) case HW_PORT2: /*REG_CR_EXT- BIT[1:0]-Network Type for port 2*/ val8 = rtw_read8(adapter, MSR1) & 0xFC; val8 |= net_type; rtw_write8(adapter, MSR1, val8); break; case HW_PORT3: /*REG_CR_EXT- BIT[3:2]-Network Type for port 3*/ val8 = rtw_read8(adapter, MSR1) & 0xF3; val8 |= net_type << 2; rtw_write8(adapter, MSR1, val8); break; case HW_PORT4: /*REG_CR_EXT- BIT[5:4]-Network Type for port 4*/ val8 = rtw_read8(adapter, MSR1) & 0xCF; val8 |= net_type << 4; rtw_write8(adapter, MSR1, val8); break; #endif /* CONFIG_RTL8814A | CONFIG_RTL8822B */ default: RTW_INFO("[WARN] "ADPT_FMT"- invalid hw port -%d\n", ADPT_ARG(adapter), adapter->hw_port); rtw_warn_on(1); break; } #endif /* !RTW_HALMAC */ } static void hw_var_set_bcn_interval(struct _ADAPTER *a, u16 interval) { #ifdef RTW_HALMAC rtw_halmac_set_bcn_interval(adapter_to_dvobj(a), a->hw_port, interval); #else /* !RTW_HALMAC */ RTW_ERR(FUNC_ADPT_FMT ": Not implemented yet!!\n", FUNC_ADPT_ARG(a)); rtw_warn_on(1); #endif /* !RTW_HALMAC */ } void hw_var_port_switch(_adapter *adapter) { #ifdef CONFIG_CONCURRENT_MODE #ifdef CONFIG_RUNTIME_PORT_SWITCH /* 0x102: MSR 0x550: REG_BCN_CTRL 0x551: REG_BCN_CTRL_1 0x55A: REG_ATIMWND 0x560: REG_TSFTR 0x568: REG_TSFTR1 0x570: REG_ATIMWND_1 0x610: REG_MACID 0x618: REG_BSSID 0x700: REG_MACID1 0x708: REG_BSSID1 */ int i; u8 msr; u8 bcn_ctrl; u8 bcn_ctrl_1; u8 atimwnd[2]; u8 atimwnd_1[2]; u8 tsftr[8]; u8 tsftr_1[8]; u8 macid[6]; u8 bssid[6]; u8 macid_1[6]; u8 bssid_1[6]; u8 hw_port; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); _adapter *iface = NULL; msr = rtw_read8(adapter, MSR); bcn_ctrl = rtw_read8(adapter, REG_BCN_CTRL); bcn_ctrl_1 = rtw_read8(adapter, REG_BCN_CTRL_1); for (i = 0; i < 2; i++) atimwnd[i] = rtw_read8(adapter, REG_ATIMWND + i); for (i = 0; i < 2; i++) atimwnd_1[i] = rtw_read8(adapter, REG_ATIMWND_1 + i); for (i = 0; i < 8; i++) tsftr[i] = rtw_read8(adapter, REG_TSFTR + i); for (i = 0; i < 8; i++) tsftr_1[i] = rtw_read8(adapter, REG_TSFTR1 + i); for (i = 0; i < 6; i++) macid[i] = rtw_read8(adapter, REG_MACID + i); for (i = 0; i < 6; i++) bssid[i] = rtw_read8(adapter, REG_BSSID + i); for (i = 0; i < 6; i++) macid_1[i] = rtw_read8(adapter, REG_MACID1 + i); for (i = 0; i < 6; i++) bssid_1[i] = rtw_read8(adapter, REG_BSSID1 + i); #ifdef DBG_RUNTIME_PORT_SWITCH RTW_INFO(FUNC_ADPT_FMT" before switch\n" "msr:0x%02x\n" "bcn_ctrl:0x%02x\n" "bcn_ctrl_1:0x%02x\n" "atimwnd:0x%04x\n" "atimwnd_1:0x%04x\n" "tsftr:%llu\n" "tsftr1:%llu\n" "macid:"MAC_FMT"\n" "bssid:"MAC_FMT"\n" "macid_1:"MAC_FMT"\n" "bssid_1:"MAC_FMT"\n" , FUNC_ADPT_ARG(adapter) , msr , bcn_ctrl , bcn_ctrl_1 , *((u16 *)atimwnd) , *((u16 *)atimwnd_1) , *((u64 *)tsftr) , *((u64 *)tsftr_1) , MAC_ARG(macid) , MAC_ARG(bssid) , MAC_ARG(macid_1) , MAC_ARG(bssid_1) ); #endif /* DBG_RUNTIME_PORT_SWITCH */ /* disable bcn function, disable update TSF */ rtw_write8(adapter, REG_BCN_CTRL, (bcn_ctrl & (~EN_BCN_FUNCTION)) | DIS_TSF_UDT); rtw_write8(adapter, REG_BCN_CTRL_1, (bcn_ctrl_1 & (~EN_BCN_FUNCTION)) | DIS_TSF_UDT); /* switch msr */ msr = (msr & 0xf0) | ((msr & 0x03) << 2) | ((msr & 0x0c) >> 2); rtw_write8(adapter, MSR, msr); /* write port0 */ rtw_write8(adapter, REG_BCN_CTRL, bcn_ctrl_1 & ~EN_BCN_FUNCTION); for (i = 0; i < 2; i++) rtw_write8(adapter, REG_ATIMWND + i, atimwnd_1[i]); for (i = 0; i < 8; i++) rtw_write8(adapter, REG_TSFTR + i, tsftr_1[i]); for (i = 0; i < 6; i++) rtw_write8(adapter, REG_MACID + i, macid_1[i]); for (i = 0; i < 6; i++) rtw_write8(adapter, REG_BSSID + i, bssid_1[i]); /* write port1 */ rtw_write8(adapter, REG_BCN_CTRL_1, bcn_ctrl & ~EN_BCN_FUNCTION); for (i = 0; i < 2; i++) rtw_write8(adapter, REG_ATIMWND_1 + i, atimwnd[i]); for (i = 0; i < 8; i++) rtw_write8(adapter, REG_TSFTR1 + i, tsftr[i]); for (i = 0; i < 6; i++) rtw_write8(adapter, REG_MACID1 + i, macid[i]); for (i = 0; i < 6; i++) rtw_write8(adapter, REG_BSSID1 + i, bssid[i]); /* write bcn ctl */ #ifdef CONFIG_BT_COEXIST /* always enable port0 beacon function for PSTDMA */ if (IS_HARDWARE_TYPE_8723B(adapter) || IS_HARDWARE_TYPE_8703B(adapter) || IS_HARDWARE_TYPE_8723D(adapter)) bcn_ctrl_1 |= EN_BCN_FUNCTION; /* always disable port1 beacon function for PSTDMA */ if (IS_HARDWARE_TYPE_8723B(adapter) || IS_HARDWARE_TYPE_8703B(adapter)) bcn_ctrl &= ~EN_BCN_FUNCTION; #endif rtw_write8(adapter, REG_BCN_CTRL, bcn_ctrl_1); rtw_write8(adapter, REG_BCN_CTRL_1, bcn_ctrl); if (adapter->iface_id == IFACE_ID0) iface = dvobj->padapters[IFACE_ID1]; else if (adapter->iface_id == IFACE_ID1) iface = dvobj->padapters[IFACE_ID0]; if (adapter->hw_port == HW_PORT0) { adapter->hw_port = HW_PORT1; iface->hw_port = HW_PORT0; RTW_PRINT("port switch - port0("ADPT_FMT"), port1("ADPT_FMT")\n", ADPT_ARG(iface), ADPT_ARG(adapter)); } else { adapter->hw_port = HW_PORT0; iface->hw_port = HW_PORT1; RTW_PRINT("port switch - port0("ADPT_FMT"), port1("ADPT_FMT")\n", ADPT_ARG(adapter), ADPT_ARG(iface)); } #ifdef DBG_RUNTIME_PORT_SWITCH msr = rtw_read8(adapter, MSR); bcn_ctrl = rtw_read8(adapter, REG_BCN_CTRL); bcn_ctrl_1 = rtw_read8(adapter, REG_BCN_CTRL_1); for (i = 0; i < 2; i++) atimwnd[i] = rtw_read8(adapter, REG_ATIMWND + i); for (i = 0; i < 2; i++) atimwnd_1[i] = rtw_read8(adapter, REG_ATIMWND_1 + i); for (i = 0; i < 8; i++) tsftr[i] = rtw_read8(adapter, REG_TSFTR + i); for (i = 0; i < 8; i++) tsftr_1[i] = rtw_read8(adapter, REG_TSFTR1 + i); for (i = 0; i < 6; i++) macid[i] = rtw_read8(adapter, REG_MACID + i); for (i = 0; i < 6; i++) bssid[i] = rtw_read8(adapter, REG_BSSID + i); for (i = 0; i < 6; i++) macid_1[i] = rtw_read8(adapter, REG_MACID1 + i); for (i = 0; i < 6; i++) bssid_1[i] = rtw_read8(adapter, REG_BSSID1 + i); RTW_INFO(FUNC_ADPT_FMT" after switch\n" "msr:0x%02x\n" "bcn_ctrl:0x%02x\n" "bcn_ctrl_1:0x%02x\n" "atimwnd:%u\n" "atimwnd_1:%u\n" "tsftr:%llu\n" "tsftr1:%llu\n" "macid:"MAC_FMT"\n" "bssid:"MAC_FMT"\n" "macid_1:"MAC_FMT"\n" "bssid_1:"MAC_FMT"\n" , FUNC_ADPT_ARG(adapter) , msr , bcn_ctrl , bcn_ctrl_1 , *((u16 *)atimwnd) , *((u16 *)atimwnd_1) , *((u64 *)tsftr) , *((u64 *)tsftr_1) , MAC_ARG(macid) , MAC_ARG(bssid) , MAC_ARG(macid_1) , MAC_ARG(bssid_1) ); #endif /* DBG_RUNTIME_PORT_SWITCH */ #endif /* CONFIG_RUNTIME_PORT_SWITCH */ #endif /* CONFIG_CONCURRENT_MODE */ } const char *const _h2c_msr_role_str[] = { "RSVD", "STA", "AP", "GC", "GO", "TDLS", "ADHOC", "MESH", "INVALID", }; #ifdef CONFIG_FW_MULTI_PORT_SUPPORT s32 rtw_hal_set_default_port_id_cmd(_adapter *adapter, u8 mac_id) { s32 ret = _SUCCESS; u8 parm[H2C_DEFAULT_PORT_ID_LEN] = {0}; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); SET_H2CCMD_DFTPID_PORT_ID(parm, adapter->hw_port); SET_H2CCMD_DFTPID_MAC_ID(parm, mac_id); RTW_DBG_DUMP("DFT port id parm:", parm, H2C_DEFAULT_PORT_ID_LEN); RTW_INFO("%s port_id :%d, mad_id:%d\n", __func__, adapter->hw_port, mac_id); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_DEFAULT_PORT_ID, H2C_DEFAULT_PORT_ID_LEN, parm); dvobj->default_port_id = adapter->hw_port; return ret; } s32 rtw_set_default_port_id(_adapter *adapter) { s32 ret = _SUCCESS; struct sta_info *psta; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); if (adapter->hw_port == dvobj->default_port_id) return ret; if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) { psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); if (psta) ret = rtw_hal_set_default_port_id_cmd(adapter, psta->cmn.mac_id); } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { } else { } return ret; } s32 rtw_set_ps_rsvd_page(_adapter *adapter) { s32 ret = _SUCCESS; u16 media_status_rpt = RT_MEDIA_CONNECT; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); if (adapter->hw_port == dvobj->default_port_id) return ret; rtw_hal_set_hwreg(adapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)&media_status_rpt); return ret; } #endif #ifdef CONFIG_P2P_PS #ifdef RTW_HALMAC void rtw_set_p2p_ps_offload_cmd(_adapter *adapter, u8 p2p_ps_state) { PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter); struct wifidirect_info *pwdinfo = &adapter->wdinfo; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); struct sta_priv *pstapriv = &adapter->stapriv; struct sta_info *psta; HAL_P2P_PS_PARA p2p_ps_para; int status = -1; u8 i; _rtw_memset(&p2p_ps_para, 0, sizeof(HAL_P2P_PS_PARA)); _rtw_memcpy((&p2p_ps_para) , &hal->p2p_ps_offload , sizeof(hal->p2p_ps_offload)); (&p2p_ps_para)->p2p_port_id = adapter->hw_port; (&p2p_ps_para)->p2p_group = 0; psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); if (psta) { (&p2p_ps_para)->p2p_macid = psta->cmn.mac_id; } else { if (p2p_ps_state != P2P_PS_DISABLE) { RTW_ERR("%s , psta was NULL\n", __func__); return; } } switch (p2p_ps_state) { case P2P_PS_DISABLE: RTW_INFO("P2P_PS_DISABLE\n"); _rtw_memset(&p2p_ps_para , 0, sizeof(HAL_P2P_PS_PARA)); break; case P2P_PS_ENABLE: RTW_INFO("P2P_PS_ENABLE\n"); /* update CTWindow value. */ if (pwdinfo->ctwindow > 0) { (&p2p_ps_para)->ctwindow_en = 1; (&p2p_ps_para)->ctwindow_length = pwdinfo->ctwindow; /*RTW_INFO("%s , ctwindow_length = %d\n" , __func__ , (&p2p_ps_para)->ctwindow_length);*/ } if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) { (&p2p_ps_para)->offload_en = 1; if (pwdinfo->role == P2P_ROLE_GO) { (&p2p_ps_para)->role = 1; (&p2p_ps_para)->all_sta_sleep = 0; } else (&p2p_ps_para)->role = 0; (&p2p_ps_para)->discovery = 0; } /* hw only support 2 set of NoA */ for (i = 0; i < pwdinfo->noa_num; i++) { /* To control the register setting for which NOA */ (&p2p_ps_para)->noa_sel = i; (&p2p_ps_para)->noa_en = 1; /* config P2P NoA Descriptor Register */ /* config NOA duration */ (&p2p_ps_para)->noa_duration_para = pwdinfo->noa_duration[i]; /* config NOA interval */ (&p2p_ps_para)->noa_interval_para = pwdinfo->noa_interval[i]; /* config NOA start time */ (&p2p_ps_para)->noa_start_time_para = pwdinfo->noa_start_time[i]; /* config NOA count */ (&p2p_ps_para)->noa_count_para = pwdinfo->noa_count[i]; /*RTW_INFO("%s , noa_duration_para = %d , noa_interval_para = %d , noa_start_time_para = %d , noa_count_para = %d\n" , __func__ , (&p2p_ps_para)->noa_duration_para , (&p2p_ps_para)->noa_interval_para , (&p2p_ps_para)->noa_start_time_para , (&p2p_ps_para)->noa_count_para);*/ status = rtw_halmac_p2pps(adapter_to_dvobj(adapter) , (&p2p_ps_para)); if (status == -1) RTW_ERR("%s , rtw_halmac_p2pps fail\n", __func__); } break; case P2P_PS_SCAN: /*This feature FW not ready 20161116 YiWei*/ return; RTW_INFO("P2P_PS_SCAN\n"); (&p2p_ps_para)->discovery = 1; /* (&p2p_ps_para)->ctwindow_length = pwdinfo->ctwindow; (&p2p_ps_para)->noa_duration_para = pwdinfo->noa_duration[0]; (&p2p_ps_para)->noa_interval_para = pwdinfo->noa_interval[0]; (&p2p_ps_para)->noa_start_time_para = pwdinfo->noa_start_time[0]; (&p2p_ps_para)->noa_count_para = pwdinfo->noa_count[0]; */ break; case P2P_PS_SCAN_DONE: /*This feature FW not ready 20161116 YiWei*/ return; RTW_INFO("P2P_PS_SCAN_DONE\n"); (&p2p_ps_para)->discovery = 0; /* pwdinfo->p2p_ps_state = P2P_PS_ENABLE; (&p2p_ps_para)->ctwindow_length = pwdinfo->ctwindow; (&p2p_ps_para)->noa_duration_para = pwdinfo->noa_duration[0]; (&p2p_ps_para)->noa_interval_para = pwdinfo->noa_interval[0]; (&p2p_ps_para)->noa_start_time_para = pwdinfo->noa_start_time[0]; (&p2p_ps_para)->noa_count_para = pwdinfo->noa_count[0]; */ break; default: break; } if (p2p_ps_state != P2P_PS_ENABLE || (&p2p_ps_para)->noa_en == 0) { status = rtw_halmac_p2pps(adapter_to_dvobj(adapter) , (&p2p_ps_para)); if (status == -1) RTW_ERR("%s , rtw_halmac_p2pps fail\n", __func__); } _rtw_memcpy(&hal->p2p_ps_offload , (&p2p_ps_para) , sizeof(hal->p2p_ps_offload)); } #endif /* RTW_HALMAC */ #endif /* CONFIG_P2P */ /* * rtw_hal_set_FwMediaStatusRpt_cmd - * * @adapter: * @opmode: 0:disconnect, 1:connect * @miracast: 0:it's not in miracast scenario. 1:it's in miracast scenario * @miracast_sink: 0:source. 1:sink * @role: The role of this macid. 0:rsvd. 1:STA. 2:AP. 3:GC. 4:GO. 5:TDLS * @macid: * @macid_ind: 0:update Media Status to macid. 1:update Media Status from macid to macid_end * @macid_end: */ s32 rtw_hal_set_FwMediaStatusRpt_cmd(_adapter *adapter, bool opmode, bool miracast, bool miracast_sink, u8 role, u8 macid, bool macid_ind, u8 macid_end) { struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl; u8 parm[H2C_MEDIA_STATUS_RPT_LEN] = {0}; int i; s32 ret; SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, opmode); SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, macid_ind); SET_H2CCMD_MSRRPT_PARM_MIRACAST(parm, miracast); SET_H2CCMD_MSRRPT_PARM_MIRACAST_SINK(parm, miracast_sink); SET_H2CCMD_MSRRPT_PARM_ROLE(parm, role); SET_H2CCMD_MSRRPT_PARM_MACID(parm, macid); SET_H2CCMD_MSRRPT_PARM_MACID_END(parm, macid_end); #ifdef CONFIG_FW_MULTI_PORT_SUPPORT SET_H2CCMD_MSRRPT_PARM_PORT_NUM(parm, adapter->hw_port); #endif RTW_DBG_DUMP("MediaStatusRpt parm:", parm, H2C_MEDIA_STATUS_RPT_LEN); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, parm); if (ret != _SUCCESS) goto exit; #if defined(CONFIG_RTL8188E) if (rtw_get_chip_type(adapter) == RTL8188E) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); /* 8188E FW doesn't set macid no link, driver does it by self */ if (opmode) rtw_hal_set_hwreg(adapter, HW_VAR_MACID_LINK, &macid); else rtw_hal_set_hwreg(adapter, HW_VAR_MACID_NOLINK, &macid); /* for 8188E RA */ #if (RATE_ADAPTIVE_SUPPORT == 1) if (hal_data->fw_ractrl == _FALSE) { u8 max_macid; max_macid = rtw_search_max_mac_id(adapter); rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, &max_macid); } #endif } #endif #if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) /* TODO: this should move to IOT issue area */ if (rtw_get_chip_type(adapter) == RTL8812 || rtw_get_chip_type(adapter) == RTL8821 ) { if (MLME_IS_STA(adapter)) Hal_PatchwithJaguar_8812(adapter, opmode); } #endif SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0); if (macid_ind == 0) macid_end = macid; for (i = macid; macid <= macid_end; macid++) { rtw_macid_ctl_set_h2c_msr(macid_ctl, macid, parm[0]); if (!opmode) { rtw_macid_ctl_set_bw(macid_ctl, macid, CHANNEL_WIDTH_20); rtw_macid_ctl_set_vht_en(macid_ctl, macid, 0); rtw_macid_ctl_set_rate_bmp0(macid_ctl, macid, 0); rtw_macid_ctl_set_rate_bmp1(macid_ctl, macid, 0); } } if (!opmode) rtw_update_tx_rate_bmp(adapter_to_dvobj(adapter)); exit: return ret; } inline s32 rtw_hal_set_FwMediaStatusRpt_single_cmd(_adapter *adapter, bool opmode, bool miracast, bool miracast_sink, u8 role, u8 macid) { return rtw_hal_set_FwMediaStatusRpt_cmd(adapter, opmode, miracast, miracast_sink, role, macid, 0, 0); } inline s32 rtw_hal_set_FwMediaStatusRpt_range_cmd(_adapter *adapter, bool opmode, bool miracast, bool miracast_sink, u8 role, u8 macid, u8 macid_end) { return rtw_hal_set_FwMediaStatusRpt_cmd(adapter, opmode, miracast, miracast_sink, role, macid, 1, macid_end); } void rtw_hal_set_FwRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) { struct hal_ops *pHalFunc = &padapter->hal_func; u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0}; u8 ret = 0; RTW_INFO("RsvdPageLoc: ProbeRsp=%d PsPoll=%d Null=%d QoSNull=%d BTNull=%d\n", rsvdpageloc->LocProbeRsp, rsvdpageloc->LocPsPoll, rsvdpageloc->LocNullData, rsvdpageloc->LocQosNull, rsvdpageloc->LocBTQosNull); SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp); SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); SET_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull); ret = rtw_hal_fill_h2c_cmd(padapter, H2C_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); } #ifdef CONFIG_GPIO_WAKEUP void rtw_hal_switch_gpio_wl_ctrl(_adapter *padapter, u8 index, u8 enable) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); if (IS_8723D_SERIES(pHalData->version_id) || IS_8822B_SERIES(pHalData->version_id)) rtw_hal_set_hwreg(padapter, HW_SET_GPIO_WL_CTRL, (u8 *)(&enable)); /* * Switch GPIO_13, GPIO_14 to wlan control, or pull GPIO_13,14 MUST fail. * It happended at 8723B/8192E/8821A. New IC will check multi function GPIO, * and implement HAL function. * TODO: GPIO_8 multi function? */ if ((index == 13 || index == 14) #if defined(CONFIG_RTL8821A) && defined(CONFIG_SDIO_HCI) /* 8821A's LED2 circuit(used by HW_LED strategy) needs enable WL GPIO control of GPIO[14:13], can't disable */ && (!IS_HW_LED_STRATEGY(rtw_led_get_strategy(padapter)) || enable) #endif ) rtw_hal_set_hwreg(padapter, HW_SET_GPIO_WL_CTRL, (u8 *)(&enable)); } void rtw_hal_set_output_gpio(_adapter *padapter, u8 index, u8 outputval) { if (index <= 7) { /* config GPIO mode */ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(index)); /* config GPIO Sel */ /* 0: input */ /* 1: output */ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 2) | BIT(index)); /* set output value */ if (outputval) { rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) | BIT(index)); } else { rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) & ~BIT(index)); } } else if (index <= 15) { /* 88C Series: */ /* index: 11~8 transform to 3~0 */ /* 8723 Series: */ /* index: 12~8 transform to 4~0 */ index -= 8; /* config GPIO mode */ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 3) & ~BIT(index)); /* config GPIO Sel */ /* 0: input */ /* 1: output */ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 2) | BIT(index)); /* set output value */ if (outputval) { rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) | BIT(index)); } else { rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) & ~BIT(index)); } } else { RTW_INFO("%s: invalid GPIO%d=%d\n", __FUNCTION__, index, outputval); } } void rtw_hal_set_input_gpio(_adapter *padapter, u8 index) { if (index <= 7) { /* config GPIO mode */ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(index)); /* config GPIO Sel */ /* 0: input */ /* 1: output */ rtw_write8(padapter, REG_GPIO_PIN_CTRL + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL + 2) & ~BIT(index)); } else if (index <= 15) { /* 88C Series: */ /* index: 11~8 transform to 3~0 */ /* 8723 Series: */ /* index: 12~8 transform to 4~0 */ index -= 8; /* config GPIO mode */ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 3, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 3) & ~BIT(index)); /* config GPIO Sel */ /* 0: input */ /* 1: output */ rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 2, rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 2) & ~BIT(index)); } else RTW_INFO("%s: invalid GPIO%d\n", __func__, index); } #endif void rtw_hal_set_FwAoacRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) { struct hal_ops *pHalFunc = &padapter->hal_func; struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; u8 res = 0, count = 0, ret = 0; #ifdef CONFIG_WOWLAN u8 u1H2CAoacRsvdPageParm[H2C_AOAC_RSVDPAGE_LOC_LEN] = {0}; RTW_INFO("%s: RWC: %d ArpRsp: %d NbrAdv: %d LocNDPInfo: %d\n", __func__, rsvdpageloc->LocRemoteCtrlInfo, rsvdpageloc->LocArpRsp, rsvdpageloc->LocNbrAdv, rsvdpageloc->LocNDPInfo); RTW_INFO("%s:GtkRsp: %d GtkInfo: %d ProbeReq: %d NetworkList: %d\n", __func__, rsvdpageloc->LocGTKRsp, rsvdpageloc->LocGTKInfo, rsvdpageloc->LocProbeReq, rsvdpageloc->LocNetList); if (check_fwstate(pmlmepriv, _FW_LINKED)) { SET_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocRemoteCtrlInfo); SET_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocArpRsp); SET_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(u1H2CAoacRsvdPageParm, rsvdpageloc->LocNbrAdv); SET_H2CCMD_AOAC_RSVDPAGE_LOC_NDP_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocNDPInfo); #ifdef CONFIG_GTK_OL SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKRsp); SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKInfo); SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKEXTMEM); #endif /* CONFIG_GTK_OL */ ret = rtw_hal_fill_h2c_cmd(padapter, H2C_AOAC_RSVD_PAGE, H2C_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); RTW_INFO("AOAC Report=%d\n", rsvdpageloc->LocAOACReport); _rtw_memset(&u1H2CAoacRsvdPageParm, 0, sizeof(u1H2CAoacRsvdPageParm)); SET_H2CCMD_AOAC_RSVDPAGE_LOC_AOAC_REPORT(u1H2CAoacRsvdPageParm, rsvdpageloc->LocAOACReport); ret = rtw_hal_fill_h2c_cmd(padapter, H2C_AOAC_RSVDPAGE3, H2C_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); pwrpriv->wowlan_aoac_rpt_loc = rsvdpageloc->LocAOACReport; } #ifdef CONFIG_PNO_SUPPORT else { if (!pwrpriv->wowlan_in_resume) { RTW_INFO("NLO_INFO=%d\n", rsvdpageloc->LocPNOInfo); _rtw_memset(&u1H2CAoacRsvdPageParm, 0, sizeof(u1H2CAoacRsvdPageParm)); SET_H2CCMD_AOAC_RSVDPAGE_LOC_NLO_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocPNOInfo); ret = rtw_hal_fill_h2c_cmd(padapter, H2C_AOAC_RSVDPAGE3, H2C_AOAC_RSVDPAGE_LOC_LEN, u1H2CAoacRsvdPageParm); } } #endif /* CONFIG_PNO_SUPPORT */ #endif /* CONFIG_WOWLAN */ } #ifdef DBG_FW_DEBUG_MSG_PKT void rtw_hal_set_fw_dbg_msg_pkt_rsvd_page_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) { struct hal_ops *pHalFunc = &padapter->hal_func; u8 u1H2C_fw_dbg_msg_pkt_parm[H2C_FW_DBG_MSG_PKT_LEN] = {0}; u8 ret = 0; RTW_INFO("RsvdPageLoc: loc_fw_dbg_msg_pkt =%d\n", rsvdpageloc->loc_fw_dbg_msg_pkt); SET_H2CCMD_FW_DBG_MSG_PKT_EN(u1H2C_fw_dbg_msg_pkt_parm, 1); SET_H2CCMD_RSVDPAGE_LOC_FW_DBG_MSG_PKT(u1H2C_fw_dbg_msg_pkt_parm, rsvdpageloc->loc_fw_dbg_msg_pkt); ret = rtw_hal_fill_h2c_cmd(padapter, H2C_FW_DBG_MSG_PKT, H2C_FW_DBG_MSG_PKT_LEN, u1H2C_fw_dbg_msg_pkt_parm); } #endif /*DBG_FW_DEBUG_MSG_PKT*/ /*#define DBG_GET_RSVD_PAGE*/ int rtw_hal_get_rsvd_page(_adapter *adapter, u32 page_offset, u32 page_num, u8 *buffer, u32 buffer_size) { u32 addr = 0, size = 0, count = 0; u32 page_size = 0, data_low = 0, data_high = 0; u16 txbndy = 0, offset = 0; u8 i = 0; bool rst = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size); addr = page_offset * page_size; size = page_num * page_size; if (buffer_size < size) { RTW_ERR("%s buffer_size(%d) < get page total size(%d)\n", __func__, buffer_size, size); return rst; } #ifdef RTW_HALMAC if (rtw_halmac_dump_fifo(adapter_to_dvobj(adapter), 2, addr, size, buffer) < 0) rst = _FALSE; else rst = _TRUE; #else txbndy = rtw_read8(adapter, REG_TDECTRL + 1); offset = (txbndy + page_offset) * page_size / 8; count = (buffer_size / 8) + 1; rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, 0x69); for (i = 0 ; i < count ; i++) { rtw_write32(adapter, REG_PKTBUF_DBG_CTRL, offset + i); data_low = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L); data_high = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H); _rtw_memcpy(buffer + (i * 8), &data_low, sizeof(data_low)); _rtw_memcpy(buffer + ((i * 8) + 4), &data_high, sizeof(data_high)); } rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, 0x0); rst = _TRUE; #endif /*RTW_HALMAC*/ #ifdef DBG_GET_RSVD_PAGE RTW_INFO("%s [page_offset:%d , page_num:%d][start_addr:0x%04x , size:%d]\n", __func__, page_offset, page_num, addr, size); RTW_INFO_DUMP("\n", buffer, size); RTW_INFO(" ==================================================\n"); #endif return rst; } void rtw_dump_rsvd_page(void *sel, _adapter *adapter, u8 page_offset, u8 page_num) { u32 page_size = 0; u8 *buffer = NULL; u32 buf_size = 0; if (page_num == 0) return; RTW_PRINT_SEL(sel, "======= RSVD PAGE DUMP =======\n"); RTW_PRINT_SEL(sel, "page_offset:%d, page_num:%d\n", page_offset, page_num); rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size); if (page_size) { buf_size = page_size * page_num; buffer = rtw_zvmalloc(buf_size); if (buffer) { rtw_hal_get_rsvd_page(adapter, page_offset, page_num, buffer, buf_size); RTW_DUMP_SEL(sel, buffer, buf_size); rtw_vmfree(buffer, buf_size); } else RTW_PRINT_SEL(sel, "ERROR - rsvd_buf mem allocate failed\n"); } else RTW_PRINT_SEL(sel, "ERROR - Tx page size is zero ??\n"); RTW_PRINT_SEL(sel, "==========================\n"); } #ifdef CONFIG_SUPPORT_FIFO_DUMP void rtw_dump_fifo(void *sel, _adapter *adapter, u8 fifo_sel, u32 fifo_addr, u32 fifo_size) { u8 *buffer = NULL; u8 buff_size = 0; static const char * const fifo_sel_str[] = { "TX", "RX", "RSVD_PAGE", "REPORT", "LLT", "RXBUF_FW" }; if (fifo_sel > 5) { RTW_ERR("fifo_sel:%d invalid\n", fifo_sel); return; } RTW_PRINT_SEL(sel, "========= FIFO DUMP =========\n"); RTW_PRINT_SEL(sel, "%s FIFO DUMP [start_addr:0x%04x , size:%d]\n", fifo_sel_str[fifo_sel], fifo_addr, fifo_size); if (fifo_size) { buff_size = RND4(fifo_size); buffer = rtw_zvmalloc(buff_size); if (buffer == NULL) buff_size = 0; } rtw_halmac_dump_fifo(adapter_to_dvobj(adapter), fifo_sel, fifo_addr, buff_size, buffer); if (buffer) { RTW_DUMP_SEL(sel, buffer, fifo_size); rtw_vmfree(buffer, buff_size); } RTW_PRINT_SEL(sel, "==========================\n"); } #endif #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) static void rtw_hal_force_enable_rxdma(_adapter *adapter) { RTW_INFO("%s: Set 0x690=0x00\n", __func__); rtw_write8(adapter, REG_WOW_CTRL, (rtw_read8(adapter, REG_WOW_CTRL) & 0xf0)); RTW_PRINT("%s: Release RXDMA\n", __func__); rtw_write32(adapter, REG_RXPKT_NUM, (rtw_read32(adapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN))); } #if defined(CONFIG_RTL8188E) static void rtw_hal_disable_tx_report(_adapter *adapter) { rtw_write8(adapter, REG_TX_RPT_CTRL, ((rtw_read8(adapter, REG_TX_RPT_CTRL) & ~BIT(1))) & ~BIT(5)); RTW_INFO("disable TXRPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); } static void rtw_hal_enable_tx_report(_adapter *adapter) { rtw_write8(adapter, REG_TX_RPT_CTRL, ((rtw_read8(adapter, REG_TX_RPT_CTRL) | BIT(1))) | BIT(5)); RTW_INFO("enable TX_RPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); } #endif static void rtw_hal_release_rx_dma(_adapter *adapter) { u32 val32 = 0; val32 = rtw_read32(adapter, REG_RXPKT_NUM); rtw_write32(adapter, REG_RXPKT_NUM, (val32 & (~RW_RELEASE_EN))); RTW_INFO("%s, [0x%04x]: 0x%08x\n", __func__, REG_RXPKT_NUM, (val32 & (~RW_RELEASE_EN))); } static u8 rtw_hal_pause_rx_dma(_adapter *adapter) { PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter); u8 ret = 0; s8 trycnt = 100; u32 tmp = 0; int res = 0; /* RX DMA stop */ RTW_PRINT("Pause DMA\n"); rtw_write32(adapter, REG_RXPKT_NUM, (rtw_read32(adapter, REG_RXPKT_NUM) | RW_RELEASE_EN)); do { if ((rtw_read32(adapter, REG_RXPKT_NUM) & RXDMA_IDLE)) { #ifdef CONFIG_USB_HCI /* stop interface before leave */ if (_TRUE == hal->usb_intf_start) { rtw_intf_stop(adapter); RTW_ENABLE_FUNC(adapter, DF_RX_BIT); RTW_ENABLE_FUNC(adapter, DF_TX_BIT); } #endif /* CONFIG_USB_HCI */ RTW_PRINT("RX_DMA_IDLE is true\n"); ret = _SUCCESS; break; } #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) else { res = RecvOnePkt(adapter); RTW_PRINT("RecvOnePkt Result: %d\n", res); } #endif /* CONFIG_SDIO_HCI || CONFIG_GSPI_HCI */ #ifdef CONFIG_USB_HCI else { /* to avoid interface start repeatedly */ if (_FALSE == hal->usb_intf_start) rtw_intf_start(adapter); } #endif /* CONFIG_USB_HCI */ } while (trycnt--); if (trycnt < 0) { tmp = rtw_read16(adapter, REG_RXPKT_NUM + 2); RTW_PRINT("Stop RX DMA failed......\n"); RTW_PRINT("%s, RXPKT_NUM: 0x%02x\n", __func__, ((tmp & 0xFF00) >> 8)); if (tmp & BIT(3)) RTW_PRINT("%s, RX DMA has req\n", __func__); else RTW_PRINT("%s, RX DMA no req\n", __func__); ret = _FAIL; } return ret; } #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) #ifndef RTW_HALMAC static u8 rtw_hal_enable_cpwm2(_adapter *adapter) { u8 ret = 0; int res = 0; u32 tmp = 0; #ifdef CONFIG_GPIO_WAKEUP return _SUCCESS; #else RTW_PRINT("%s\n", __func__); res = sdio_local_read(adapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); if (!res) RTW_INFO("read SDIO_REG_HIMR: 0x%08x\n", tmp); else RTW_INFO("sdio_local_read fail\n"); tmp = SDIO_HIMR_CPWM2_MSK; res = sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); if (!res) { res = sdio_local_read(adapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); RTW_INFO("read again SDIO_REG_HIMR: 0x%08x\n", tmp); ret = _SUCCESS; } else { RTW_INFO("sdio_local_write fail\n"); ret = _FAIL; } return ret; #endif /* CONFIG_CPIO_WAKEUP */ } #endif #endif /* CONFIG_SDIO_HCI, CONFIG_GSPI_HCI */ #endif /* CONFIG_WOWLAN || CONFIG_AP_WOWLAN */ #ifdef CONFIG_WOWLAN /* * rtw_hal_check_wow_ctrl * chk_type: _TRUE means to check enable, if 0x690 & bit1 (for 8051), WOW enable successful. * If 0x1C7 == 0 (for 3081), WOW enable successful. * _FALSE means to check disable, if 0x690 & bit1 (for 8051), WOW disable fail. * If 0x120 & bit16 || 0x284 & bit18 (for 3081), WOW disable fail. */ static u8 rtw_hal_check_wow_ctrl(_adapter *adapter, u8 chk_type) { u32 fe1_imr = 0xFF, rxpkt_num = 0xFF; u8 mstatus = 0; u8 reason = 0xFF; u8 trycnt = 25; u8 res = _FALSE; if (IS_HARDWARE_TYPE_JAGUAR2(adapter)) { if (chk_type) { reason = rtw_read8(adapter, REG_WOWLAN_WAKE_REASON); RTW_INFO("%s reason:0x%02x\n", __func__, reason); while (reason && trycnt > 1) { reason = rtw_read8(adapter, REG_WOWLAN_WAKE_REASON); RTW_PRINT("Loop index: %d :0x%02x\n", trycnt, reason); trycnt--; rtw_msleep_os(20); } if (!reason) res = _TRUE; else res = _FALSE; } else { /* Wait FW to cleare 0x120 bit16, 0x284 bit18 to 0 */ fe1_imr = rtw_read32(adapter, REG_FE1IMR); /* RxDone IMR for 3081 */ rxpkt_num = rtw_read32(adapter, REG_RXPKT_NUM); /* Release RXDMA */ RTW_PRINT("%s REG_FE1IMR (reg120): 0x%x, REG_RXPKT_NUM(reg284): 0x%x\n", __func__, fe1_imr, rxpkt_num); while (((fe1_imr & BIT_FS_RXDONE_INT_EN) || (rxpkt_num & BIT_RW_RELEASE_EN)) && trycnt > 1) { rtw_msleep_os(20); fe1_imr = rtw_read32(adapter, REG_FE1IMR); rxpkt_num = rtw_read32(adapter, REG_RXPKT_NUM); RTW_PRINT("Loop index: %d :0x%x, 0x%x\n", trycnt, fe1_imr, rxpkt_num); trycnt--; } if ((fe1_imr & BIT_FS_RXDONE_INT_EN) || (rxpkt_num & BIT_RW_RELEASE_EN)) res = _FALSE; else res = _TRUE; } } else { mstatus = rtw_read8(adapter, REG_WOW_CTRL); RTW_INFO("%s mstatus:0x%02x\n", __func__, mstatus); if (chk_type) { while (!(mstatus & BIT1) && trycnt > 1) { mstatus = rtw_read8(adapter, REG_WOW_CTRL); RTW_PRINT("Loop index: %d :0x%02x\n", trycnt, mstatus); trycnt--; rtw_msleep_os(20); } if (mstatus & BIT1) res = _TRUE; else res = _FALSE; } else { while (mstatus & BIT1 && trycnt > 1) { mstatus = rtw_read8(adapter, REG_WOW_CTRL); RTW_PRINT("Loop index: %d :0x%02x\n", trycnt, mstatus); trycnt--; rtw_msleep_os(20); } if (mstatus & BIT1) res = _FALSE; else res = _TRUE; } } RTW_PRINT("%s check_type: %d res: %d trycnt: %d\n", __func__, chk_type, res, (25 - trycnt)); return res; } #ifdef CONFIG_PNO_SUPPORT static u8 rtw_hal_check_pno_enabled(_adapter *adapter) { struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); u8 res = 0, count = 0; u8 ret = _FALSE; if (ppwrpriv->wowlan_pno_enable && ppwrpriv->wowlan_in_resume == _FALSE) { res = rtw_read8(adapter, REG_PNO_STATUS); while (!(res & BIT(7)) && count < 25) { RTW_INFO("[%d] cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", count, res); res = rtw_read8(adapter, REG_PNO_STATUS); count++; rtw_msleep_os(2); } if (res & BIT(7)) ret = _TRUE; else ret = _FALSE; RTW_INFO("cmd: 0x81 REG_PNO_STATUS: ret(%d)\n", ret); } return ret; } #endif static void rtw_hal_backup_rate(_adapter *adapter) { RTW_INFO("%s\n", __func__); /* backup data rate to register 0x8b for wowlan FW */ rtw_write8(adapter, 0x8d, 1); rtw_write8(adapter, 0x8c, 0); rtw_write8(adapter, 0x8f, 0x40); rtw_write8(adapter, 0x8b, rtw_read8(adapter, 0x2f0)); } #ifdef CONFIG_GTK_OL static void rtw_hal_fw_sync_cam_id(_adapter *adapter) { struct mlme_priv *pmlmepriv = &adapter->mlmepriv; int cam_id, index = 0; u8 *addr = NULL; if (!MLME_IS_STA(adapter)) return; addr = get_bssid(pmlmepriv); if (addr == NULL) { RTW_INFO("%s: get bssid MAC addr fail!!\n", __func__); return; } rtw_clean_dk_section(adapter); do { cam_id = rtw_camid_search(adapter, addr, index, 1); if (cam_id == -1) RTW_INFO("%s: cam_id: %d, key_id:%d\n", __func__, cam_id, index); else rtw_sec_cam_swap(adapter, cam_id, index); index++; } while (index < 4); rtw_write8(adapter, REG_SECCFG, 0xcc); } static void rtw_hal_update_gtk_offload_info(_adapter *adapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct security_priv *psecuritypriv = &adapter->securitypriv; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; _irqL irqL; u8 get_key[16]; u8 gtk_id = 0, offset = 0, i = 0, sz = 0; u64 replay_count = 0, tmp_iv_hdr = 0, pkt_pn = 0; if (!MLME_IS_STA(adapter)) return; _rtw_memset(get_key, 0, sizeof(get_key)); _rtw_memcpy(&replay_count, paoac_rpt->replay_counter_eapol_key, 8); /*read gtk key index*/ gtk_id = paoac_rpt->key_index; if (gtk_id == 5 || gtk_id == 0) { RTW_INFO("%s no rekey event happened.\n", __func__); } else if (gtk_id > 0 && gtk_id < 4) { RTW_INFO("%s update security key.\n", __func__); /*read key from sec-cam,for DK ,keyindex is equal to cam-id*/ rtw_sec_read_cam_ent(adapter, gtk_id, NULL, NULL, get_key); rtw_clean_hw_dk_cam(adapter); if (_rtw_camid_is_gk(adapter, gtk_id)) { _enter_critical_bh(&cam_ctl->lock, &irqL); _rtw_memcpy(&dvobj->cam_cache[gtk_id].key, get_key, 16); _exit_critical_bh(&cam_ctl->lock, &irqL); } else { struct setkey_parm parm_gtk; parm_gtk.algorithm = paoac_rpt->security_type; parm_gtk.keyid = gtk_id; _rtw_memcpy(parm_gtk.key, get_key, 16); setkey_hdl(adapter, (u8 *)&parm_gtk); } /*update key into related sw variable and sec-cam cache*/ psecuritypriv->dot118021XGrpKeyid = gtk_id; _rtw_memcpy(&psecuritypriv->dot118021XGrpKey[gtk_id], get_key, 16); /* update SW TKIP TX/RX MIC value */ if (psecuritypriv->dot118021XGrpPrivacy == _TKIP_) { offset = RTW_KEK_LEN + RTW_TKIP_MIC_LEN; _rtw_memcpy( &psecuritypriv->dot118021XGrptxmickey[gtk_id], &(paoac_rpt->group_key[offset]), RTW_TKIP_MIC_LEN); offset = RTW_KEK_LEN; _rtw_memcpy( &psecuritypriv->dot118021XGrprxmickey[gtk_id], &(paoac_rpt->group_key[offset]), RTW_TKIP_MIC_LEN); } RTW_PRINT("GTK (%d) "KEY_FMT"\n", gtk_id, KEY_ARG(psecuritypriv->dot118021XGrpKey[gtk_id].skey)); } /* Update broadcast RX IV */ if (psecuritypriv->dot118021XGrpPrivacy == _AES_) { sz = sizeof(psecuritypriv->iv_seq[0]); for (i = 0 ; i < 4 ; i++) { _rtw_memcpy(&tmp_iv_hdr, paoac_rpt->rxgtk_iv[i], sz); tmp_iv_hdr = le64_to_cpu(tmp_iv_hdr); pkt_pn = CCMPH_2_PN(tmp_iv_hdr); _rtw_memcpy(psecuritypriv->iv_seq[i], &pkt_pn, sz); } } rtw_clean_dk_section(adapter); rtw_write8(adapter, REG_SECCFG, 0x0c); #ifdef CONFIG_GTK_OL_DBG /* if (gtk_keyindex != 5) */ dump_sec_cam(RTW_DBGDUMP, adapter); dump_sec_cam_cache(RTW_DBGDUMP, adapter); #endif } #endif /*CONFIG_GTK_OL*/ static void rtw_dump_aoac_rpt(_adapter *adapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; int i = 0; RTW_INFO_DUMP("[AOAC-RPT] IV -", paoac_rpt->iv, 8); RTW_INFO_DUMP("[AOAC-RPT] Replay counter of EAPOL key - ", paoac_rpt->replay_counter_eapol_key, 8); RTW_INFO_DUMP("[AOAC-RPT] Group key - ", paoac_rpt->group_key, 32); RTW_INFO("[AOAC-RPT] Key Index - %d\n", paoac_rpt->key_index); RTW_INFO("[AOAC-RPT] Security Type - %d\n", paoac_rpt->security_type); RTW_INFO("[AOAC-RPT] wow_pattern_idx - %d\n", paoac_rpt->wow_pattern_idx); RTW_INFO("[AOAC-RPT] version_info - %d\n", paoac_rpt->version_info); RTW_INFO_DUMP("[AOAC-RPT] RX PTK IV-", paoac_rpt->rxptk_iv, 8); RTW_INFO_DUMP("[AOAC-RPT] RX GTK[0] IV-", paoac_rpt->rxgtk_iv[0], 8); RTW_INFO_DUMP("[AOAC-RPT] RX GTK[1] IV-", paoac_rpt->rxgtk_iv[1], 8); RTW_INFO_DUMP("[AOAC-RPT] RX GTK[2] IV-", paoac_rpt->rxgtk_iv[2], 8); RTW_INFO_DUMP("[AOAC-RPT] RX GTK[3] IV-", paoac_rpt->rxgtk_iv[3], 8); } static void rtw_hal_get_aoac_rpt(_adapter *adapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; u32 page_offset = 0, page_number = 0; u32 page_size = 0, buf_size = 0; u8 *buffer = NULL; u8 i = 0, tmp = 0; int ret = -1; /* read aoac report from rsvd page */ page_offset = pwrctl->wowlan_aoac_rpt_loc; page_number = 1; rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size); buf_size = page_size * page_number; buffer = rtw_zvmalloc(buf_size); if (buffer == NULL) { RTW_ERR("%s buffer allocate failed size(%d)\n", __func__, buf_size); return; } RTW_INFO("Get AOAC Report from rsvd page_offset:%d\n", page_offset); ret = rtw_hal_get_rsvd_page(adapter, page_offset, page_number, buffer, buf_size); if (ret == _FALSE) { RTW_ERR("%s get aoac report failed\n", __func__); rtw_warn_on(1); goto _exit; } _rtw_memset(paoac_rpt, 0, sizeof(struct aoac_report)); _rtw_memcpy(paoac_rpt, buffer, sizeof(struct aoac_report)); for (i = 0 ; i < 4 ; i++) { tmp = paoac_rpt->replay_counter_eapol_key[i]; paoac_rpt->replay_counter_eapol_key[i] = paoac_rpt->replay_counter_eapol_key[7 - i]; paoac_rpt->replay_counter_eapol_key[7 - i] = tmp; } rtw_dump_aoac_rpt(adapter); _exit: if (buffer) rtw_vmfree(buffer, buf_size); } static void rtw_hal_update_tx_iv(_adapter *adapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; struct sta_info *psta; struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct security_priv *psecpriv = &adapter->securitypriv; u16 val16 = 0; u32 val32 = 0; u64 txiv = 0; u8 *pval = NULL; psta = rtw_get_stainfo(&adapter->stapriv, get_my_bssid(&pmlmeinfo->network)); /* Update TX iv data. */ pval = (u8 *)&paoac_rpt->iv; if (psecpriv->dot11PrivacyAlgrthm == _TKIP_) { val16 = ((u16)(paoac_rpt->iv[2]) << 0) + ((u16)(paoac_rpt->iv[0]) << 8); val32 = ((u32)(paoac_rpt->iv[4]) << 0) + ((u32)(paoac_rpt->iv[5]) << 8) + ((u32)(paoac_rpt->iv[6]) << 16) + ((u32)(paoac_rpt->iv[7]) << 24); } else if (psecpriv->dot11PrivacyAlgrthm == _AES_) { val16 = ((u16)(paoac_rpt->iv[0]) << 0) + ((u16)(paoac_rpt->iv[1]) << 8); val32 = ((u32)(paoac_rpt->iv[4]) << 0) + ((u32)(paoac_rpt->iv[5]) << 8) + ((u32)(paoac_rpt->iv[6]) << 16) + ((u32)(paoac_rpt->iv[7]) << 24); } if (psta) { txiv = val16 + ((u64)val32 << 16); if (txiv != 0) psta->dot11txpn.val = txiv; } } static void rtw_hal_update_sw_security_info(_adapter *adapter) { struct security_priv *psecpriv = &adapter->securitypriv; u8 sz = sizeof (psecpriv->iv_seq); rtw_hal_update_tx_iv(adapter); #ifdef CONFIG_GTK_OL if (psecpriv->binstallKCK_KEK == _TRUE && psecpriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) rtw_hal_update_gtk_offload_info(adapter); #else _rtw_memset(psecpriv->iv_seq, 0, sz); #endif } static u8 rtw_hal_set_keep_alive_cmd(_adapter *adapter, u8 enable, u8 pkt_type) { struct hal_ops *pHalFunc = &adapter->hal_func; u8 u1H2CKeepAliveParm[H2C_KEEP_ALIVE_CTRL_LEN] = {0}; u8 adopt = 1, check_period = 5; u8 ret = _FAIL; SET_H2CCMD_KEEPALIVE_PARM_ENABLE(u1H2CKeepAliveParm, enable); SET_H2CCMD_KEEPALIVE_PARM_ADOPT(u1H2CKeepAliveParm, adopt); SET_H2CCMD_KEEPALIVE_PARM_PKT_TYPE(u1H2CKeepAliveParm, pkt_type); SET_H2CCMD_KEEPALIVE_PARM_CHECK_PERIOD(u1H2CKeepAliveParm, check_period); #ifdef CONFIG_FW_MULTI_PORT_SUPPORT SET_H2CCMD_KEEPALIVE_PARM_PORT_NUM(u1H2CKeepAliveParm, adapter->hw_port); RTW_INFO("%s(): enable = %d, port = %d\n", __func__, enable, adapter->hw_port); #else RTW_INFO("%s(): enable = %d\n", __func__, enable); #endif ret = rtw_hal_fill_h2c_cmd(adapter, H2C_KEEP_ALIVE, H2C_KEEP_ALIVE_CTRL_LEN, u1H2CKeepAliveParm); return ret; } static u8 rtw_hal_set_disconnect_decision_cmd(_adapter *adapter, u8 enable) { struct hal_ops *pHalFunc = &adapter->hal_func; u8 u1H2CDisconDecisionParm[H2C_DISCON_DECISION_LEN] = {0}; u8 adopt = 1, check_period = 30, trypkt_num = 5; u8 ret = _FAIL; SET_H2CCMD_DISCONDECISION_PARM_ENABLE(u1H2CDisconDecisionParm, enable); SET_H2CCMD_DISCONDECISION_PARM_ADOPT(u1H2CDisconDecisionParm, adopt); SET_H2CCMD_DISCONDECISION_PARM_CHECK_PERIOD(u1H2CDisconDecisionParm, check_period); SET_H2CCMD_DISCONDECISION_PARM_TRY_PKT_NUM(u1H2CDisconDecisionParm, trypkt_num); #ifdef CONFIG_FW_MULTI_PORT_SUPPORT SET_H2CCMD_DISCONDECISION_PORT_NUM(u1H2CDisconDecisionParm, adapter->hw_port); RTW_INFO("%s(): enable = %d, port = %d\n", __func__, enable, adapter->hw_port); #else RTW_INFO("%s(): enable = %d\n", __func__, enable); #endif ret = rtw_hal_fill_h2c_cmd(adapter, H2C_DISCON_DECISION, H2C_DISCON_DECISION_LEN, u1H2CDisconDecisionParm); return ret; } static u8 rtw_hal_set_wowlan_ctrl_cmd(_adapter *adapter, u8 enable, u8 change_unit) { struct registry_priv *registry_par = &adapter->registrypriv; struct security_priv *psecpriv = &adapter->securitypriv; struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); struct hal_ops *pHalFunc = &adapter->hal_func; u8 u1H2CWoWlanCtrlParm[H2C_WOWLAN_LEN] = {0}; u8 discont_wake = 0, gpionum = 0, gpio_dur = 0; u8 hw_unicast = 0, gpio_pulse_cnt = 0, gpio_pulse_en = 0; u8 sdio_wakeup_enable = 1; u8 gpio_high_active = 0; u8 magic_pkt = 0; u8 gpio_unit = 0; /*0: 64ns, 1: 8ms*/ u8 ret = _FAIL; #ifdef CONFIG_DIS_UPHY u8 dis_uphy = 0, dis_uphy_unit = 0, dis_uphy_time = 0; #endif /* CONFIG_DIS_UPHY */ #ifdef CONFIG_GPIO_WAKEUP gpio_high_active = ppwrpriv->is_high_active; gpionum = WAKEUP_GPIO_IDX; sdio_wakeup_enable = 0; #endif /* CONFIG_GPIO_WAKEUP */ if (!ppwrpriv->wowlan_pno_enable && registry_par->wakeup_event & BIT(0)) magic_pkt = enable; if ((registry_par->wakeup_event & BIT(1)) && (psecpriv->dot11PrivacyAlgrthm == _WEP40_ || psecpriv->dot11PrivacyAlgrthm == _WEP104_)) hw_unicast = 1; if (registry_par->wakeup_event & BIT(2)) discont_wake = enable; RTW_INFO("%s(): enable=%d change_unit=%d\n", __func__, enable, change_unit); /* time = (gpio_dur/2) * gpio_unit, default:256 ms */ if (enable && change_unit) { gpio_dur = 0x40; gpio_unit = 1; gpio_pulse_en = 1; } #ifdef CONFIG_PLATFORM_ARM_RK3188 if (enable) { gpio_pulse_en = 1; gpio_pulse_cnt = 0x04; } #endif SET_H2CCMD_WOWLAN_FUNC_ENABLE(u1H2CWoWlanCtrlParm, enable); SET_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(u1H2CWoWlanCtrlParm, enable); SET_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(u1H2CWoWlanCtrlParm, magic_pkt); SET_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(u1H2CWoWlanCtrlParm, hw_unicast); SET_H2CCMD_WOWLAN_ALL_PKT_DROP(u1H2CWoWlanCtrlParm, 0); SET_H2CCMD_WOWLAN_GPIO_ACTIVE(u1H2CWoWlanCtrlParm, gpio_high_active); #ifdef CONFIG_GTK_OL if (psecpriv->binstallKCK_KEK == _TRUE && psecpriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) SET_H2CCMD_WOWLAN_REKEY_WAKE_UP(u1H2CWoWlanCtrlParm, 0); else SET_H2CCMD_WOWLAN_REKEY_WAKE_UP(u1H2CWoWlanCtrlParm, 1); #else SET_H2CCMD_WOWLAN_REKEY_WAKE_UP(u1H2CWoWlanCtrlParm, enable); #endif SET_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(u1H2CWoWlanCtrlParm, discont_wake); SET_H2CCMD_WOWLAN_GPIONUM(u1H2CWoWlanCtrlParm, gpionum); SET_H2CCMD_WOWLAN_DATAPIN_WAKE_UP(u1H2CWoWlanCtrlParm, sdio_wakeup_enable); SET_H2CCMD_WOWLAN_GPIO_DURATION(u1H2CWoWlanCtrlParm, gpio_dur); SET_H2CCMD_WOWLAN_CHANGE_UNIT(u1H2CWoWlanCtrlParm, gpio_unit); SET_H2CCMD_WOWLAN_GPIO_PULSE_EN(u1H2CWoWlanCtrlParm, gpio_pulse_en); SET_H2CCMD_WOWLAN_GPIO_PULSE_COUNT(u1H2CWoWlanCtrlParm, gpio_pulse_cnt); #ifdef CONFIG_WAKEUP_GPIO_INPUT_MODE if (enable) SET_H2CCMD_WOWLAN_GPIO_INPUT_EN(u1H2CWoWlanCtrlParm, 1); #endif #ifdef CONFIG_DIS_UPHY if (enable) { dis_uphy = 1; /* time unit: 0 -> ms, 1 -> 256 ms*/ dis_uphy_unit = 1; dis_uphy_time = 0x4; } SET_H2CCMD_WOWLAN_DIS_UPHY(u1H2CWoWlanCtrlParm, dis_uphy); SET_H2CCMD_WOWLAN_HOST_2_DEV(u1H2CWoWlanCtrlParm, 1); SET_H2CCMD_WOWLAN_DIS_UPHY_UNIT(u1H2CWoWlanCtrlParm, dis_uphy_unit); SET_H2CCMD_WOWLAN_DIS_UPHY_TIME(u1H2CWoWlanCtrlParm, dis_uphy_time); #endif /* CONFIG_DIS_UPHY */ ret = rtw_hal_fill_h2c_cmd(adapter, H2C_WOWLAN, H2C_WOWLAN_LEN, u1H2CWoWlanCtrlParm); return ret; } static u8 rtw_hal_set_remote_wake_ctrl_cmd(_adapter *adapter, u8 enable) { struct hal_ops *pHalFunc = &adapter->hal_func; struct security_priv *psecuritypriv = &(adapter->securitypriv); struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); struct registry_priv *pregistrypriv = &adapter->registrypriv; u8 u1H2CRemoteWakeCtrlParm[H2C_REMOTE_WAKE_CTRL_LEN] = {0}; u8 ret = _FAIL, count = 0; RTW_INFO("%s(): enable=%d\n", __func__, enable); if (!ppwrpriv->wowlan_pno_enable) { SET_H2CCMD_REMOTE_WAKECTRL_ENABLE( u1H2CRemoteWakeCtrlParm, enable); SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN( u1H2CRemoteWakeCtrlParm, 1); #ifdef CONFIG_GTK_OL if (psecuritypriv->binstallKCK_KEK == _TRUE && psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN( u1H2CRemoteWakeCtrlParm, 1); } else { RTW_INFO("no kck kek\n"); SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN( u1H2CRemoteWakeCtrlParm, 0); } #endif /* CONFIG_GTK_OL */ #ifdef CONFIG_IPV6 if (ppwrpriv->wowlan_ns_offload_en == _TRUE) { RTW_INFO("enable NS offload\n"); SET_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN( u1H2CRemoteWakeCtrlParm, enable); } /* * filter NetBios name service pkt to avoid being waked-up * by this kind of unicast pkt this exceptional modification * is used for match competitor's behavior */ SET_H2CCMD_REMOTE_WAKE_CTRL_NBNS_FILTER_EN( u1H2CRemoteWakeCtrlParm, enable); #endif /*CONFIG_IPV6*/ if ((psecuritypriv->dot11PrivacyAlgrthm == _AES_) || (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) || (psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_)) { SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION( u1H2CRemoteWakeCtrlParm, 0); } else { SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION( u1H2CRemoteWakeCtrlParm, 1); } if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_ && psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { SET_H2CCMD_REMOTE_WAKE_CTRL_TKIP_OFFLOAD_EN( u1H2CRemoteWakeCtrlParm, enable); if (IS_HARDWARE_TYPE_8188E(adapter) || IS_HARDWARE_TYPE_8812(adapter)) { SET_H2CCMD_REMOTE_WAKE_CTRL_TKIP_OFFLOAD_EN( u1H2CRemoteWakeCtrlParm, 0); SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION( u1H2CRemoteWakeCtrlParm, 1); } } SET_H2CCMD_REMOTE_WAKE_CTRL_FW_PARSING_UNTIL_WAKEUP( u1H2CRemoteWakeCtrlParm, 1); } #ifdef CONFIG_PNO_SUPPORT else { SET_H2CCMD_REMOTE_WAKECTRL_ENABLE( u1H2CRemoteWakeCtrlParm, enable); SET_H2CCMD_REMOTE_WAKE_CTRL_NLO_OFFLOAD_EN( u1H2CRemoteWakeCtrlParm, enable); } #endif #ifdef CONFIG_P2P_WOWLAN if (_TRUE == ppwrpriv->wowlan_p2p_mode) { RTW_INFO("P2P OFFLOAD ENABLE\n"); SET_H2CCMD_REMOTE_WAKE_CTRL_P2P_OFFLAD_EN(u1H2CRemoteWakeCtrlParm, 1); } else { RTW_INFO("P2P OFFLOAD DISABLE\n"); SET_H2CCMD_REMOTE_WAKE_CTRL_P2P_OFFLAD_EN(u1H2CRemoteWakeCtrlParm, 0); } #endif /* CONFIG_P2P_WOWLAN */ ret = rtw_hal_fill_h2c_cmd(adapter, H2C_REMOTE_WAKE_CTRL, H2C_REMOTE_WAKE_CTRL_LEN, u1H2CRemoteWakeCtrlParm); return ret; } static u8 rtw_hal_set_global_info_cmd(_adapter *adapter, u8 group_alg, u8 pairwise_alg) { struct hal_ops *pHalFunc = &adapter->hal_func; u8 ret = _FAIL; u8 u1H2CAOACGlobalInfoParm[H2C_AOAC_GLOBAL_INFO_LEN] = {0}; RTW_INFO("%s(): group_alg=%d pairwise_alg=%d\n", __func__, group_alg, pairwise_alg); SET_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(u1H2CAOACGlobalInfoParm, pairwise_alg); SET_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(u1H2CAOACGlobalInfoParm, group_alg); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_AOAC_GLOBAL_INFO, H2C_AOAC_GLOBAL_INFO_LEN, u1H2CAOACGlobalInfoParm); return ret; } #ifdef CONFIG_PNO_SUPPORT static u8 rtw_hal_set_scan_offload_info_cmd(_adapter *adapter, PRSVDPAGE_LOC rsvdpageloc, u8 enable) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); struct hal_ops *pHalFunc = &adapter->hal_func; u8 u1H2CScanOffloadInfoParm[H2C_SCAN_OFFLOAD_CTRL_LEN] = {0}; u8 res = 0, count = 0, ret = _FAIL; RTW_INFO("%s: loc_probe_packet:%d, loc_scan_info: %d loc_ssid_info:%d\n", __func__, rsvdpageloc->LocProbePacket, rsvdpageloc->LocScanInfo, rsvdpageloc->LocSSIDInfo); SET_H2CCMD_AOAC_NLO_FUN_EN(u1H2CScanOffloadInfoParm, enable); SET_H2CCMD_AOAC_NLO_IPS_EN(u1H2CScanOffloadInfoParm, enable); SET_H2CCMD_AOAC_RSVDPAGE_LOC_SCAN_INFO(u1H2CScanOffloadInfoParm, rsvdpageloc->LocScanInfo); SET_H2CCMD_AOAC_RSVDPAGE_LOC_PROBE_PACKET(u1H2CScanOffloadInfoParm, rsvdpageloc->LocProbePacket); /* SET_H2CCMD_AOAC_RSVDPAGE_LOC_SSID_INFO(u1H2CScanOffloadInfoParm, rsvdpageloc->LocSSIDInfo); */ ret = rtw_hal_fill_h2c_cmd(adapter, H2C_D0_SCAN_OFFLOAD_INFO, H2C_SCAN_OFFLOAD_CTRL_LEN, u1H2CScanOffloadInfoParm); return ret; } #endif /* CONFIG_PNO_SUPPORT */ void rtw_hal_set_fw_wow_related_cmd(_adapter *padapter, u8 enable) { struct security_priv *psecpriv = &padapter->securitypriv; struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct registry_priv *pregistry = &padapter->registrypriv; struct sta_info *psta = NULL; u16 media_status_rpt; u8 pkt_type = 0; u8 ret = _SUCCESS; RTW_PRINT("+%s()+: enable=%d\n", __func__, enable); rtw_hal_set_wowlan_ctrl_cmd(padapter, enable, _FALSE); if (enable) { rtw_hal_set_global_info_cmd(padapter, psecpriv->dot118021XGrpPrivacy, psecpriv->dot11PrivacyAlgrthm); if (!(ppwrpriv->wowlan_pno_enable)) { if (pregistry->wakeup_event & BIT(2)) rtw_hal_set_disconnect_decision_cmd(padapter, enable); #ifdef CONFIG_ARP_KEEP_ALIVE if ((psecpriv->dot11PrivacyAlgrthm == _WEP40_) || (psecpriv->dot11PrivacyAlgrthm == _WEP104_)) pkt_type = 0; else pkt_type = 1; #else pkt_type = 0; #endif /* CONFIG_ARP_KEEP_ALIVE */ rtw_hal_set_keep_alive_cmd(padapter, enable, pkt_type); } rtw_hal_set_remote_wake_ctrl_cmd(padapter, enable); #ifdef CONFIG_PNO_SUPPORT rtw_hal_check_pno_enabled(padapter); #endif /* CONFIG_PNO_SUPPORT */ } else { #if 0 { u32 PageSize = 0; rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, (u8 *)&PageSize); dump_TX_FIFO(padapter, 4, PageSize); } #endif rtw_hal_set_remote_wake_ctrl_cmd(padapter, enable); } RTW_PRINT("-%s()-\n", __func__); } #endif /* CONFIG_WOWLAN */ #ifdef CONFIG_AP_WOWLAN static u8 rtw_hal_set_ap_wowlan_ctrl_cmd(_adapter *adapter, u8 enable) { struct security_priv *psecpriv = &adapter->securitypriv; struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); struct hal_ops *pHalFunc = &adapter->hal_func; u8 u1H2CAPWoWlanCtrlParm[H2C_AP_WOW_GPIO_CTRL_LEN] = {0}; u8 gpionum = 0, gpio_dur = 0; u8 gpio_pulse = enable; u8 sdio_wakeup_enable = 1; u8 gpio_high_active = 0; u8 ret = _FAIL; #ifdef CONFIG_GPIO_WAKEUP gpio_high_active = ppwrpriv->is_high_active; gpionum = WAKEUP_GPIO_IDX; sdio_wakeup_enable = 0; #endif /*CONFIG_GPIO_WAKEUP*/ RTW_INFO("%s(): enable=%d\n", __func__, enable); SET_H2CCMD_AP_WOW_GPIO_CTRL_INDEX(u1H2CAPWoWlanCtrlParm, gpionum); SET_H2CCMD_AP_WOW_GPIO_CTRL_PLUS(u1H2CAPWoWlanCtrlParm, gpio_pulse); SET_H2CCMD_AP_WOW_GPIO_CTRL_HIGH_ACTIVE(u1H2CAPWoWlanCtrlParm, gpio_high_active); SET_H2CCMD_AP_WOW_GPIO_CTRL_EN(u1H2CAPWoWlanCtrlParm, enable); SET_H2CCMD_AP_WOW_GPIO_CTRL_DURATION(u1H2CAPWoWlanCtrlParm, gpio_dur); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_AP_WOW_GPIO_CTRL, H2C_AP_WOW_GPIO_CTRL_LEN, u1H2CAPWoWlanCtrlParm); return ret; } static u8 rtw_hal_set_ap_offload_ctrl_cmd(_adapter *adapter, u8 enable) { struct hal_ops *pHalFunc = &adapter->hal_func; u8 u1H2CAPOffloadCtrlParm[H2C_WOWLAN_LEN] = {0}; u8 ret = _FAIL; RTW_INFO("%s(): bFuncEn=%d\n", __func__, enable); SET_H2CCMD_AP_WOWLAN_EN(u1H2CAPOffloadCtrlParm, enable); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_AP_OFFLOAD, H2C_AP_OFFLOAD_LEN, u1H2CAPOffloadCtrlParm); return ret; } static u8 rtw_hal_set_ap_ps_cmd(_adapter *adapter, u8 enable) { struct hal_ops *pHalFunc = &adapter->hal_func; u8 ap_ps_parm[H2C_AP_PS_LEN] = {0}; u8 ret = _FAIL; RTW_INFO("%s(): enable=%d\n" , __func__ , enable); SET_H2CCMD_AP_WOW_PS_EN(ap_ps_parm, enable); #ifndef CONFIG_USB_HCI SET_H2CCMD_AP_WOW_PS_32K_EN(ap_ps_parm, enable); #endif /*CONFIG_USB_HCI*/ SET_H2CCMD_AP_WOW_PS_RF(ap_ps_parm, enable); if (enable) SET_H2CCMD_AP_WOW_PS_DURATION(ap_ps_parm, 0x32); else SET_H2CCMD_AP_WOW_PS_DURATION(ap_ps_parm, 0x0); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_SAP_PS_, H2C_AP_PS_LEN, ap_ps_parm); return ret; } static void rtw_hal_set_ap_rsvdpage_loc_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) { struct hal_ops *pHalFunc = &padapter->hal_func; u8 rsvdparm[H2C_AOAC_RSVDPAGE_LOC_LEN] = {0}; u8 ret = _FAIL, header = 0; if (pHalFunc->fill_h2c_cmd == NULL) { RTW_INFO("%s: Please hook fill_h2c_cmd first!\n", __func__); return; } header = rtw_read8(padapter, REG_BCNQ_BDNY); RTW_INFO("%s: beacon: %d, probeRsp: %d, header:0x%02x\n", __func__, rsvdpageloc->LocApOffloadBCN, rsvdpageloc->LocProbeRsp, header); SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_BCN(rsvdparm, rsvdpageloc->LocApOffloadBCN + header); ret = rtw_hal_fill_h2c_cmd(padapter, H2C_BCN_RSVDPAGE, H2C_BCN_RSVDPAGE_LEN, rsvdparm); if (ret == _FAIL) RTW_INFO("%s: H2C_BCN_RSVDPAGE cmd fail\n", __func__); rtw_msleep_os(10); _rtw_memset(&rsvdparm, 0, sizeof(rsvdparm)); SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_ProbeRsp(rsvdparm, rsvdpageloc->LocProbeRsp + header); ret = rtw_hal_fill_h2c_cmd(padapter, H2C_PROBERSP_RSVDPAGE, H2C_PROBERSP_RSVDPAGE_LEN, rsvdparm); if (ret == _FAIL) RTW_INFO("%s: H2C_PROBERSP_RSVDPAGE cmd fail\n", __func__); rtw_msleep_os(10); } static void rtw_hal_set_fw_ap_wow_related_cmd(_adapter *padapter, u8 enable) { rtw_hal_set_ap_offload_ctrl_cmd(padapter, enable); rtw_hal_set_ap_wowlan_ctrl_cmd(padapter, enable); rtw_hal_set_ap_ps_cmd(padapter, enable); } static void rtw_hal_ap_wow_enable(_adapter *padapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); struct security_priv *psecuritypriv = &padapter->securitypriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct hal_ops *pHalFunc = &padapter->hal_func; struct sta_info *psta = NULL; PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); #ifdef DBG_CHECK_FW_PS_STATE struct dvobj_priv *psdpriv = padapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; #endif /*DBG_CHECK_FW_PS_STATE*/ int res; u16 media_status_rpt; RTW_INFO("%s, WOWLAN_AP_ENABLE\n", __func__); #ifdef DBG_CHECK_FW_PS_STATE if (rtw_fw_ps_state(padapter) == _FAIL) { pdbgpriv->dbg_enwow_dload_fw_fail_cnt++; RTW_PRINT("wowlan enable no leave 32k\n"); } #endif /*DBG_CHECK_FW_PS_STATE*/ /* 1. Download WOWLAN FW*/ rtw_hal_fw_dl(padapter, _TRUE); media_status_rpt = RT_MEDIA_CONNECT; rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)&media_status_rpt); issue_beacon(padapter, 0); rtw_msleep_os(2); #if defined(CONFIG_RTL8188E) if (IS_HARDWARE_TYPE_8188E(padapter)) rtw_hal_disable_tx_report(padapter); #endif /* RX DMA stop */ res = rtw_hal_pause_rx_dma(padapter); if (res == _FAIL) RTW_PRINT("[WARNING] pause RX DMA fail\n"); #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) /* Enable CPWM2 only. */ res = rtw_hal_enable_cpwm2(padapter); if (res == _FAIL) RTW_PRINT("[WARNING] enable cpwm2 fail\n"); #endif #ifdef CONFIG_GPIO_WAKEUP rtw_hal_switch_gpio_wl_ctrl(padapter, WAKEUP_GPIO_IDX, _TRUE); #endif /* 5. Set Enable WOWLAN H2C command. */ RTW_PRINT("Set Enable AP WOWLan cmd\n"); rtw_hal_set_fw_ap_wow_related_cmd(padapter, 1); rtw_write8(padapter, REG_MCUTST_WOWLAN, 0); #ifdef CONFIG_USB_HCI rtw_mi_intf_stop(padapter); #endif #if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) /* Invoid SE0 reset signal during suspending*/ rtw_write8(padapter, REG_RSV_CTRL, 0x20); if (IS_8188F(pHalData->version_id) == FALSE) rtw_write8(padapter, REG_RSV_CTRL, 0x60); #endif } static void rtw_hal_ap_wow_disable(_adapter *padapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); struct hal_ops *pHalFunc = &padapter->hal_func; #ifdef DBG_CHECK_FW_PS_STATE struct dvobj_priv *psdpriv = padapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; #endif /*DBG_CHECK_FW_PS_STATE*/ u16 media_status_rpt; u8 val8; RTW_INFO("%s, WOWLAN_AP_DISABLE\n", __func__); /* 1. Read wakeup reason*/ pwrctl->wowlan_wake_reason = rtw_read8(padapter, REG_MCUTST_WOWLAN); RTW_PRINT("wakeup_reason: 0x%02x\n", pwrctl->wowlan_wake_reason); rtw_hal_set_fw_ap_wow_related_cmd(padapter, 0); rtw_msleep_os(2); #ifdef DBG_CHECK_FW_PS_STATE if (rtw_fw_ps_state(padapter) == _FAIL) { pdbgpriv->dbg_diswow_dload_fw_fail_cnt++; RTW_PRINT("wowlan enable no leave 32k\n"); } #endif /*DBG_CHECK_FW_PS_STATE*/ #if defined(CONFIG_RTL8188E) if (IS_HARDWARE_TYPE_8188E(padapter)) rtw_hal_enable_tx_report(padapter); #endif rtw_hal_force_enable_rxdma(padapter); rtw_hal_fw_dl(padapter, _FALSE); #ifdef CONFIG_GPIO_WAKEUP #ifdef CONFIG_WAKEUP_GPIO_INPUT_MODE if (pwrctl->is_high_active == 0) rtw_hal_set_input_gpio(padapter, WAKEUP_GPIO_IDX); else rtw_hal_set_output_gpio(padapter, WAKEUP_GPIO_IDX, 0); #else val8 = (pwrctl->is_high_active == 0) ? 1 : 0; RTW_PRINT("Set Wake GPIO to default(%d).\n", val8); rtw_hal_set_output_gpio(padapter, WAKEUP_GPIO_IDX, val8); rtw_hal_switch_gpio_wl_ctrl(padapter, WAKEUP_GPIO_IDX, _FALSE); #endif/*CONFIG_WAKEUP_GPIO_INPUT_MODE*/ #endif media_status_rpt = RT_MEDIA_CONNECT; rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)&media_status_rpt); issue_beacon(padapter, 0); } #endif /*CONFIG_AP_WOWLAN*/ #ifdef CONFIG_P2P_WOWLAN static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) { u8 *ssid_ie; sint ssid_len_ori; int len_diff = 0; ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); /* RTW_INFO("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __FUNCTION__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */ if (ssid_ie && ssid_len_ori > 0) { switch (hidden_ssid_mode) { case 1: { u8 *next_ie = ssid_ie + 2 + ssid_len_ori; u32 remain_len = 0; remain_len = ies_len - (next_ie - ies); ssid_ie[1] = 0; _rtw_memcpy(ssid_ie + 2, next_ie, remain_len); len_diff -= ssid_len_ori; break; } case 2: _rtw_memset(&ssid_ie[2], 0, ssid_len_ori); break; default: break; } } return len_diff; } static void rtw_hal_construct_P2PBeacon(_adapter *padapter, u8 *pframe, u32 *pLength) { /* struct xmit_frame *pmgntframe; */ /* struct pkt_attrib *pattrib; */ /* unsigned char *pframe; */ struct rtw_ieee80211_hdr *pwlanhdr; unsigned short *fctrl; unsigned int rate_len; struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); u32 pktlen; /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ /* _irqL irqL; * struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); * #endif */ /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; #ifdef CONFIG_P2P struct wifidirect_info *pwdinfo = &(padapter->wdinfo); #endif /* CONFIG_P2P */ /* for debug */ u8 *dbgbuf = pframe; u8 dbgbufLen = 0, index = 0; RTW_INFO("%s\n", __FUNCTION__); /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ /* _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); * #endif */ /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); /* pmlmeext->mgnt_seq++; */ set_frame_sub_type(pframe, WIFI_BEACON); pframe += sizeof(struct rtw_ieee80211_hdr_3addr); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { /* RTW_INFO("ie len=%d\n", cur_network->IELength); */ #ifdef CONFIG_P2P /* for P2P : Primary Device Type & Device Name */ u32 wpsielen = 0, insert_len = 0; u8 *wpsie = NULL; wpsie = rtw_get_wps_ie(cur_network->IEs + _FIXED_IE_LENGTH_, cur_network->IELength - _FIXED_IE_LENGTH_, NULL, &wpsielen); if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) { uint wps_offset, remainder_ielen; u8 *premainder_ie, *pframe_wscie; wps_offset = (uint)(wpsie - cur_network->IEs); premainder_ie = wpsie + wpsielen; remainder_ielen = cur_network->IELength - wps_offset - wpsielen; #ifdef CONFIG_IOCTL_CFG80211 if (pwdinfo->driver_interface == DRIVER_CFG80211) { if (pmlmepriv->wps_beacon_ie && pmlmepriv->wps_beacon_ie_len > 0) { _rtw_memcpy(pframe, cur_network->IEs, wps_offset); pframe += wps_offset; pktlen += wps_offset; _rtw_memcpy(pframe, pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len); pframe += pmlmepriv->wps_beacon_ie_len; pktlen += pmlmepriv->wps_beacon_ie_len; /* copy remainder_ie to pframe */ _rtw_memcpy(pframe, premainder_ie, remainder_ielen); pframe += remainder_ielen; pktlen += remainder_ielen; } else { _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); pframe += cur_network->IELength; pktlen += cur_network->IELength; } } else #endif /* CONFIG_IOCTL_CFG80211 */ { pframe_wscie = pframe + wps_offset; _rtw_memcpy(pframe, cur_network->IEs, wps_offset + wpsielen); pframe += (wps_offset + wpsielen); pktlen += (wps_offset + wpsielen); /* now pframe is end of wsc ie, insert Primary Device Type & Device Name */ /* Primary Device Type */ /* Type: */ *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); insert_len += 2; /* Length: */ *(u16 *)(pframe + insert_len) = cpu_to_be16(0x0008); insert_len += 2; /* Value: */ /* Category ID */ *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); insert_len += 2; /* OUI */ *(u32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI); insert_len += 4; /* Sub Category ID */ *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); insert_len += 2; /* Device Name */ /* Type: */ *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); insert_len += 2; /* Length: */ *(u16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len); insert_len += 2; /* Value: */ _rtw_memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len); insert_len += pwdinfo->device_name_len; /* update wsc ie length */ *(pframe_wscie + 1) = (wpsielen - 2) + insert_len; /* pframe move to end */ pframe += insert_len; pktlen += insert_len; /* copy remainder_ie to pframe */ _rtw_memcpy(pframe, premainder_ie, remainder_ielen); pframe += remainder_ielen; pktlen += remainder_ielen; } } else #endif /* CONFIG_P2P */ { int len_diff; _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); len_diff = update_hidden_ssid( pframe + _BEACON_IE_OFFSET_ , cur_network->IELength - _BEACON_IE_OFFSET_ , pmlmeinfo->hidden_ssid_mode ); pframe += (cur_network->IELength + len_diff); pktlen += (cur_network->IELength + len_diff); } #if 0 { u8 *wps_ie; uint wps_ielen; u8 sr = 0; wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, pattrib->pktlen - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_, NULL, &wps_ielen); if (wps_ie && wps_ielen > 0) rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); if (sr != 0) set_fwstate(pmlmepriv, WIFI_UNDER_WPS); else _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); } #endif #ifdef CONFIG_P2P if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { u32 len; #ifdef CONFIG_IOCTL_CFG80211 if (pwdinfo->driver_interface == DRIVER_CFG80211) { len = pmlmepriv->p2p_beacon_ie_len; if (pmlmepriv->p2p_beacon_ie && len > 0) _rtw_memcpy(pframe, pmlmepriv->p2p_beacon_ie, len); } else #endif /* CONFIG_IOCTL_CFG80211 */ { len = build_beacon_p2p_ie(pwdinfo, pframe); } pframe += len; pktlen += len; #ifdef CONFIG_WFD len = rtw_append_beacon_wfd_ie(padapter, pframe); pframe += len; pktlen += len; #endif } #endif /* CONFIG_P2P */ goto _issue_bcn; } /* below for ad-hoc mode */ /* timestamp will be inserted by hardware */ pframe += 8; pktlen += 8; /* beacon interval: 2 bytes */ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); pframe += 2; pktlen += 2; /* capability info: 2 bytes */ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); pframe += 2; pktlen += 2; /* SSID */ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); /* DS parameter set */ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); /* if( (pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) */ { u8 erpinfo = 0; u32 ATIMWindow; /* IBSS Parameter Set... */ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ATIMWindow = 0; pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); /* ERP IE */ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pktlen); } /* EXTERNDED SUPPORTED RATE */ if (rate_len > 8) pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); /* todo:HT for adhoc */ _issue_bcn: /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ /* pmlmepriv->update_bcn = _FALSE; * * _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); * #endif */ /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ *pLength = pktlen; #if 0 /* printf dbg msg */ dbgbufLen = pktlen; RTW_INFO("======> DBG MSG FOR CONSTRAUCT P2P BEACON\n"); for (index = 0; index < dbgbufLen; index++) printk("%x ", *(dbgbuf + index)); printk("\n"); RTW_INFO("<====== DBG MSG FOR CONSTRAUCT P2P BEACON\n"); #endif } static void rtw_hal_construct_P2PProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength) { /* struct xmit_frame *pmgntframe; */ /* struct pkt_attrib *pattrib; */ /* unsigned char *pframe; */ struct rtw_ieee80211_hdr *pwlanhdr; unsigned short *fctrl; unsigned char *mac; struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); /* WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); */ u16 beacon_interval = 100; u16 capInfo = 0; struct wifidirect_info *pwdinfo = &(padapter->wdinfo); u8 wpsie[255] = { 0x00 }; u32 wpsielen = 0, p2pielen = 0; u32 pktlen; #ifdef CONFIG_WFD u32 wfdielen = 0; #endif #ifdef CONFIG_INTEL_WIDI u8 zero_array_check[L2SDTA_SERVICE_VE_LEN] = { 0x00 }; #endif /* CONFIG_INTEL_WIDI */ /* for debug */ u8 *dbgbuf = pframe; u8 dbgbufLen = 0, index = 0; RTW_INFO("%s\n", __FUNCTION__); pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; mac = adapter_mac_addr(padapter); fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; /* DA filled by FW */ _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); /* Use the device address for BSSID field. */ _rtw_memcpy(pwlanhdr->addr3, mac, ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_frame_sub_type(fctrl, WIFI_PROBERSP); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); pframe += pktlen; /* timestamp will be inserted by hardware */ pframe += 8; pktlen += 8; /* beacon interval: 2 bytes */ _rtw_memcpy(pframe, (unsigned char *) &beacon_interval, 2); pframe += 2; pktlen += 2; /* capability info: 2 bytes */ /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */ capInfo |= cap_ShortPremble; capInfo |= cap_ShortSlot; _rtw_memcpy(pframe, (unsigned char *) &capInfo, 2); pframe += 2; pktlen += 2; /* SSID */ pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pktlen); /* supported rates... */ /* Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) */ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pktlen); /* DS parameter set */ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pktlen); #ifdef CONFIG_IOCTL_CFG80211 if (pwdinfo->driver_interface == DRIVER_CFG80211) { if (pmlmepriv->wps_probe_resp_ie != NULL && pmlmepriv->p2p_probe_resp_ie != NULL) { /* WPS IE */ _rtw_memcpy(pframe, pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len); pktlen += pmlmepriv->wps_probe_resp_ie_len; pframe += pmlmepriv->wps_probe_resp_ie_len; /* P2P IE */ _rtw_memcpy(pframe, pmlmepriv->p2p_probe_resp_ie, pmlmepriv->p2p_probe_resp_ie_len); pktlen += pmlmepriv->p2p_probe_resp_ie_len; pframe += pmlmepriv->p2p_probe_resp_ie_len; } } else #endif /* CONFIG_IOCTL_CFG80211 */ { /* Todo: WPS IE */ /* Noted by Albert 20100907 */ /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ wpsielen = 0; /* WPS OUI */ *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); wpsielen += 4; /* WPS version */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); wpsielen += 2; /* Value: */ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ #ifdef CONFIG_INTEL_WIDI /* Commented by Kurt */ /* Appended WiDi info. only if we did issued_probereq_widi(), and then we saved ven. ext. in pmlmepriv->sa_ext. */ if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE || pmlmepriv->num_p2p_sdt != 0) { /* Sec dev type */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SEC_DEV_TYPE_LIST); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); wpsielen += 2; /* Value: */ /* Category ID */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_DISPLAYS); wpsielen += 2; /* OUI */ *(u32 *)(wpsie + wpsielen) = cpu_to_be32(INTEL_DEV_TYPE_OUI); wpsielen += 4; *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_WIDI_CONSUMER_SINK); wpsielen += 2; if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE) { /* Vendor Extension */ _rtw_memcpy(wpsie + wpsielen, pmlmepriv->sa_ext, L2SDTA_SERVICE_VE_LEN); wpsielen += L2SDTA_SERVICE_VE_LEN; } } #endif /* CONFIG_INTEL_WIDI */ /* WiFi Simple Config State */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); wpsielen += 2; /* Value: */ wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; /* Not Configured. */ /* Response Type */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); wpsielen += 2; /* Value: */ wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; /* UUID-E */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); wpsielen += 2; /* Value: */ if (pwdinfo->external_uuid == 0) { _rtw_memset(wpsie + wpsielen, 0x0, 16); _rtw_memcpy(wpsie + wpsielen, mac, ETH_ALEN); } else _rtw_memcpy(wpsie + wpsielen, pwdinfo->uuid, 0x10); wpsielen += 0x10; /* Manufacturer */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007); wpsielen += 2; /* Value: */ _rtw_memcpy(wpsie + wpsielen, "Realtek", 7); wpsielen += 7; /* Model Name */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006); wpsielen += 2; /* Value: */ _rtw_memcpy(wpsie + wpsielen, "8192CU", 6); wpsielen += 6; /* Model Number */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); wpsielen += 2; /* Value: */ wpsie[wpsielen++] = 0x31; /* character 1 */ /* Serial Number */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN); wpsielen += 2; /* Value: */ _rtw_memcpy(wpsie + wpsielen, "123456" , ETH_ALEN); wpsielen += ETH_ALEN; /* Primary Device Type */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); wpsielen += 2; /* Value: */ /* Category ID */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); wpsielen += 2; /* OUI */ *(u32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); wpsielen += 4; /* Sub Category ID */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); wpsielen += 2; /* Device Name */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); wpsielen += 2; /* Value: */ _rtw_memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); wpsielen += pwdinfo->device_name_len; /* Config Method */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); wpsielen += 2; /* Value: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); wpsielen += 2; pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pktlen); p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe); pframe += p2pielen; pktlen += p2pielen; } #ifdef CONFIG_WFD wfdielen = rtw_append_probe_resp_wfd_ie(padapter, pframe); pframe += wfdielen; pktlen += wfdielen; #endif *pLength = pktlen; #if 0 /* printf dbg msg */ dbgbufLen = pktlen; RTW_INFO("======> DBG MSG FOR CONSTRAUCT P2P Probe Rsp\n"); for (index = 0; index < dbgbufLen; index++) printk("%x ", *(dbgbuf + index)); printk("\n"); RTW_INFO("<====== DBG MSG FOR CONSTRAUCT P2P Probe Rsp\n"); #endif } static void rtw_hal_construct_P2PNegoRsp(_adapter *padapter, u8 *pframe, u32 *pLength) { struct p2p_channels *ch_list = &(adapter_to_rfctl(padapter)->channel_list); unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; u8 action = P2P_PUB_ACTION_ACTION; u32 p2poui = cpu_to_be32(P2POUI); u8 oui_subtype = P2P_GO_NEGO_RESP; u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; u8 p2pielen = 0, i; uint wpsielen = 0; u16 wps_devicepassword_id = 0x0000; uint wps_devicepassword_id_len = 0; u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh; u16 len_channellist_attr = 0; u32 pktlen; u8 dialogToken = 0; /* struct xmit_frame *pmgntframe; */ /* struct pkt_attrib *pattrib; */ /* unsigned char *pframe; */ struct rtw_ieee80211_hdr *pwlanhdr; unsigned short *fctrl; struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct wifidirect_info *pwdinfo = &(padapter->wdinfo); /* WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); */ #ifdef CONFIG_WFD u32 wfdielen = 0; #endif /* for debug */ u8 *dbgbuf = pframe; u8 dbgbufLen = 0, index = 0; RTW_INFO("%s\n", __FUNCTION__); pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; /* RA, filled by FW */ _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_frame_sub_type(pframe, WIFI_ACTION); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); pframe += pktlen; pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pktlen)); /* dialog token, filled by FW */ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pktlen)); _rtw_memset(wpsie, 0x00, 255); wpsielen = 0; /* WPS Section */ wpsielen = 0; /* WPS OUI */ *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); wpsielen += 4; /* WPS version */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); wpsielen += 2; /* Value: */ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ /* Device Password ID */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); wpsielen += 2; /* Value: */ if (wps_devicepassword_id == WPS_DPID_USER_SPEC) *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); else *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); wpsielen += 2; pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pktlen); /* P2P IE Section. */ /* P2P OUI */ p2pielen = 0; p2pie[p2pielen++] = 0x50; p2pie[p2pielen++] = 0x6F; p2pie[p2pielen++] = 0x9A; p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ /* Commented by Albert 20100908 */ /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */ /* 1. Status */ /* 2. P2P Capability */ /* 3. Group Owner Intent */ /* 4. Configuration Timeout */ /* 5. Operating Channel */ /* 6. Intended P2P Interface Address */ /* 7. Channel List */ /* 8. Device Info */ /* 9. Group ID ( Only GO ) */ /* ToDo: */ /* P2P Status */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_STATUS; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); p2pielen += 2; /* Value, filled by FW */ p2pie[p2pielen++] = 1; /* P2P Capability */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); p2pielen += 2; /* Value: */ /* Device Capability Bitmap, 1 byte */ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { /* Commented by Albert 2011/03/08 */ /* According to the P2P specification */ /* if the sending device will be client, the P2P Capability should be reserved of group negotation response frame */ p2pie[p2pielen++] = 0; } else { /* Be group owner or meet the error case */ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; } /* Group Capability Bitmap, 1 byte */ if (pwdinfo->persistent_supported) p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; else p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; /* Group Owner Intent */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); p2pielen += 2; /* Value: */ if (pwdinfo->peer_intent & 0x01) { /* Peer's tie breaker bit is 1, our tie breaker bit should be 0 */ p2pie[p2pielen++] = (pwdinfo->intent << 1); } else { /* Peer's tie breaker bit is 0, our tie breaker bit should be 1 */ p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); } /* Configuration Timeout */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); p2pielen += 2; /* Value: */ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ /* Operating Channel */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); p2pielen += 2; /* Value: */ /* Country String */ p2pie[p2pielen++] = 'X'; p2pie[p2pielen++] = 'X'; /* The third byte should be set to 0x04. */ /* Described in the "Operating Channel Attribute" section. */ p2pie[p2pielen++] = 0x04; /* Operating Class */ if (pwdinfo->operating_channel <= 14) { /* Operating Class */ p2pie[p2pielen++] = 0x51; } else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) { /* Operating Class */ p2pie[p2pielen++] = 0x73; } else { /* Operating Class */ p2pie[p2pielen++] = 0x7c; } /* Channel Number */ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ /* Intended P2P Interface Address */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_INTENDED_IF_ADDR; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); p2pielen += 2; /* Value: */ _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); p2pielen += ETH_ALEN; /* Channel List */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; /* Country String(3) */ /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ /* + number of channels in all classes */ len_channellist_attr = 3 + (1 + 1) * (u16)ch_list->reg_classes + get_reg_classes_full_count(ch_list); #ifdef CONFIG_CONCURRENT_MODE if (rtw_mi_buddy_check_fwstate(padapter, _FW_LINKED)) *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); else *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); #else *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); #endif p2pielen += 2; /* Value: */ /* Country String */ p2pie[p2pielen++] = 'X'; p2pie[p2pielen++] = 'X'; /* The third byte should be set to 0x04. */ /* Described in the "Operating Channel Attribute" section. */ p2pie[p2pielen++] = 0x04; /* Channel Entry List */ #ifdef CONFIG_CONCURRENT_MODE if (rtw_mi_check_status(padapter, MI_LINKED)) { u8 union_ch = rtw_mi_get_union_chan(padapter); /* Operating Class */ if (union_ch > 14) { if (union_ch >= 149) p2pie[p2pielen++] = 0x7c; else p2pie[p2pielen++] = 0x73; } else p2pie[p2pielen++] = 0x51; /* Number of Channels */ /* Just support 1 channel and this channel is AP's channel */ p2pie[p2pielen++] = 1; /* Channel List */ p2pie[p2pielen++] = union_ch; } else #endif /* CONFIG_CONCURRENT_MODE */ { int i, j; for (j = 0; j < ch_list->reg_classes; j++) { /* Operating Class */ p2pie[p2pielen++] = ch_list->reg_class[j].reg_class; /* Number of Channels */ p2pie[p2pielen++] = ch_list->reg_class[j].channels; /* Channel List */ for (i = 0; i < ch_list->reg_class[j].channels; i++) p2pie[p2pielen++] = ch_list->reg_class[j].channel[i]; } } /* Device Info */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; /* Length: */ /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); p2pielen += 2; /* Value: */ /* P2P Device Address */ _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); p2pielen += ETH_ALEN; /* Config Method */ /* This field should be big endian. Noted by P2P specification. */ *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); p2pielen += 2; /* Primary Device Type */ /* Category ID */ *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); p2pielen += 2; /* OUI */ *(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); p2pielen += 4; /* Sub Category ID */ *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); p2pielen += 2; /* Number of Secondary Device Types */ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ /* Device Name */ /* Type: */ *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); p2pielen += 2; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); p2pielen += 2; /* Value: */ _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len); p2pielen += pwdinfo->device_name_len; if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { /* Group ID Attribute */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); p2pielen += 2; /* Value: */ /* p2P Device Address */ _rtw_memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN); p2pielen += ETH_ALEN; /* SSID */ _rtw_memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); p2pielen += pwdinfo->nego_ssidlen; } pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pktlen); #ifdef CONFIG_WFD wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe); pframe += wfdielen; pktlen += wfdielen; #endif *pLength = pktlen; #if 0 /* printf dbg msg */ dbgbufLen = pktlen; RTW_INFO("======> DBG MSG FOR CONSTRAUCT Nego Rsp\n"); for (index = 0; index < dbgbufLen; index++) printk("%x ", *(dbgbuf + index)); printk("\n"); RTW_INFO("<====== DBG MSG FOR CONSTRAUCT Nego Rsp\n"); #endif } static void rtw_hal_construct_P2PInviteRsp(_adapter *padapter, u8 *pframe, u32 *pLength) { unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; u8 action = P2P_PUB_ACTION_ACTION; u32 p2poui = cpu_to_be32(P2POUI); u8 oui_subtype = P2P_INVIT_RESP; u8 p2pie[255] = { 0x00 }; u8 p2pielen = 0, i; u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; u16 len_channellist_attr = 0; u32 pktlen; u8 dialogToken = 0; #ifdef CONFIG_WFD u32 wfdielen = 0; #endif /* struct xmit_frame *pmgntframe; */ /* struct pkt_attrib *pattrib; */ /* unsigned char *pframe; */ struct rtw_ieee80211_hdr *pwlanhdr; unsigned short *fctrl; struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct wifidirect_info *pwdinfo = &(padapter->wdinfo); /* for debug */ u8 *dbgbuf = pframe; u8 dbgbufLen = 0, index = 0; RTW_INFO("%s\n", __FUNCTION__); pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; /* RA fill by FW */ _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); /* BSSID fill by FW */ _rtw_memset(pwlanhdr->addr3, 0, ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_frame_sub_type(pframe, WIFI_ACTION); pframe += sizeof(struct rtw_ieee80211_hdr_3addr); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pktlen)); /* dialog token, filled by FW */ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pktlen)); /* P2P IE Section. */ /* P2P OUI */ p2pielen = 0; p2pie[p2pielen++] = 0x50; p2pie[p2pielen++] = 0x6F; p2pie[p2pielen++] = 0x9A; p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ /* Commented by Albert 20101005 */ /* According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */ /* 1. Status */ /* 2. Configuration Timeout */ /* 3. Operating Channel ( Only GO ) */ /* 4. P2P Group BSSID ( Only GO ) */ /* 5. Channel List */ /* P2P Status */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_STATUS; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); p2pielen += 2; /* Value: filled by FW, defult value is FAIL INFO UNAVAILABLE */ p2pie[p2pielen++] = P2P_STATUS_FAIL_INFO_UNAVAILABLE; /* Configuration Timeout */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); p2pielen += 2; /* Value: */ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ /* due to defult value is FAIL INFO UNAVAILABLE, so the following IE is not needed */ #if 0 if (status_code == P2P_STATUS_SUCCESS) { struct p2p_channels *ch_list = &(adapter_to_rfctl(padapter)->channel_list); if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { /* The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */ /* In this case, the P2P Invitation response frame should carry the two more P2P attributes. */ /* First one is operating channel attribute. */ /* Second one is P2P Group BSSID attribute. */ /* Operating Channel */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); p2pielen += 2; /* Value: */ /* Country String */ p2pie[p2pielen++] = 'X'; p2pie[p2pielen++] = 'X'; /* The third byte should be set to 0x04. */ /* Described in the "Operating Channel Attribute" section. */ p2pie[p2pielen++] = 0x04; /* Operating Class */ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ /* Channel Number */ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ /* P2P Group BSSID */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; /* Length: */ *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); p2pielen += 2; /* Value: */ /* P2P Device Address for GO */ _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); p2pielen += ETH_ALEN; } /* Channel List */ /* Type: */ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; /* Length: */ /* Country String(3) */ /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ /* + number of channels in all classes */ len_channellist_attr = 3 + (1 + 1) * (u16)ch_list->reg_classes + get_reg_classes_full_count(ch_list); #ifdef CONFIG_CONCURRENT_MODE if (rtw_mi_check_status(padapter, MI_LINKED)) *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); else *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); #else *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); #endif p2pielen += 2; /* Value: */ /* Country String */ p2pie[p2pielen++] = 'X'; p2pie[p2pielen++] = 'X'; /* The third byte should be set to 0x04. */ /* Described in the "Operating Channel Attribute" section. */ p2pie[p2pielen++] = 0x04; /* Channel Entry List */ #ifdef CONFIG_CONCURRENT_MODE if (rtw_mi_check_status(padapter, MI_LINKED)) { u8 union_ch = rtw_mi_get_union_chan(padapter); /* Operating Class */ if (union_ch > 14) { if (union_ch >= 149) p2pie[p2pielen++] = 0x7c; else p2pie[p2pielen++] = 0x73; } else p2pie[p2pielen++] = 0x51; /* Number of Channels */ /* Just support 1 channel and this channel is AP's channel */ p2pie[p2pielen++] = 1; /* Channel List */ p2pie[p2pielen++] = union_ch; } else #endif /* CONFIG_CONCURRENT_MODE */ { int i, j; for (j = 0; j < ch_list->reg_classes; j++) { /* Operating Class */ p2pie[p2pielen++] = ch_list->reg_class[j].reg_class; /* Number of Channels */ p2pie[p2pielen++] = ch_list->reg_class[j].channels; /* Channel List */ for (i = 0; i < ch_list->reg_class[j].channels; i++) p2pie[p2pielen++] = ch_list->reg_class[j].channel[i]; } } } #endif pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pktlen); #ifdef CONFIG_WFD wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe); pframe += wfdielen; pktlen += wfdielen; #endif *pLength = pktlen; #if 0 /* printf dbg msg */ dbgbufLen = pktlen; RTW_INFO("======> DBG MSG FOR CONSTRAUCT Invite Rsp\n"); for (index = 0; index < dbgbufLen; index++) printk("%x ", *(dbgbuf + index)); printk("\n"); RTW_INFO("<====== DBG MSG FOR CONSTRAUCT Invite Rsp\n"); #endif } static void rtw_hal_construct_P2PProvisionDisRsp(_adapter *padapter, u8 *pframe, u32 *pLength) { unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; u8 action = P2P_PUB_ACTION_ACTION; u8 dialogToken = 0; u32 p2poui = cpu_to_be32(P2POUI); u8 oui_subtype = P2P_PROVISION_DISC_RESP; u8 wpsie[100] = { 0x00 }; u8 wpsielen = 0; u32 pktlen; #ifdef CONFIG_WFD u32 wfdielen = 0; #endif /* struct xmit_frame *pmgntframe; */ /* struct pkt_attrib *pattrib; */ /* unsigned char *pframe; */ struct rtw_ieee80211_hdr *pwlanhdr; unsigned short *fctrl; struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct wifidirect_info *pwdinfo = &(padapter->wdinfo); /* for debug */ u8 *dbgbuf = pframe; u8 dbgbufLen = 0, index = 0; RTW_INFO("%s\n", __FUNCTION__); pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; /* RA filled by FW */ _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_frame_sub_type(pframe, WIFI_ACTION); pframe += sizeof(struct rtw_ieee80211_hdr_3addr); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pktlen)); pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pktlen)); /* dialog token, filled by FW */ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pktlen)); wpsielen = 0; /* WPS OUI */ /* *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); */ RTW_PUT_BE32(wpsie, WPSOUI); wpsielen += 4; #if 0 /* WPS version */ /* Type: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); wpsielen += 2; /* Length: */ *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); wpsielen += 2; /* Value: */ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ #endif /* Config Method */ /* Type: */ /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); */ RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); wpsielen += 2; /* Length: */ /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); */ RTW_PUT_BE16(wpsie + wpsielen, 0x0002); wpsielen += 2; /* Value: filled by FW, default value is PBC */ /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( config_method ); */ RTW_PUT_BE16(wpsie + wpsielen, WPS_CM_PUSH_BUTTON); wpsielen += 2; pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pktlen); #ifdef CONFIG_WFD wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe); pframe += wfdielen; pktlen += wfdielen; #endif *pLength = pktlen; /* printf dbg msg */ #if 0 dbgbufLen = pktlen; RTW_INFO("======> DBG MSG FOR CONSTRAUCT ProvisionDis Rsp\n"); for (index = 0; index < dbgbufLen; index++) printk("%x ", *(dbgbuf + index)); printk("\n"); RTW_INFO("<====== DBG MSG FOR CONSTRAUCT ProvisionDis Rsp\n"); #endif } u8 rtw_hal_set_FwP2PRsvdPage_cmd(_adapter *adapter, PRSVDPAGE_LOC rsvdpageloc) { u8 u1H2CP2PRsvdPageParm[H2C_P2PRSVDPAGE_LOC_LEN] = {0}; struct hal_ops *pHalFunc = &adapter->hal_func; u8 ret = _FAIL; RTW_INFO("P2PRsvdPageLoc: P2PBeacon=%d P2PProbeRsp=%d NegoRsp=%d InviteRsp=%d PDRsp=%d\n", rsvdpageloc->LocP2PBeacon, rsvdpageloc->LocP2PProbeRsp, rsvdpageloc->LocNegoRsp, rsvdpageloc->LocInviteRsp, rsvdpageloc->LocPDRsp); SET_H2CCMD_RSVDPAGE_LOC_P2P_BCN(u1H2CP2PRsvdPageParm, rsvdpageloc->LocProbeRsp); SET_H2CCMD_RSVDPAGE_LOC_P2P_PROBE_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocPsPoll); SET_H2CCMD_RSVDPAGE_LOC_P2P_NEGO_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocNullData); SET_H2CCMD_RSVDPAGE_LOC_P2P_INVITE_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocQosNull); SET_H2CCMD_RSVDPAGE_LOC_P2P_PD_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocBTQosNull); /* FillH2CCmd8723B(padapter, H2C_8723B_P2P_OFFLOAD_RSVD_PAGE, H2C_P2PRSVDPAGE_LOC_LEN, u1H2CP2PRsvdPageParm); */ ret = rtw_hal_fill_h2c_cmd(adapter, H2C_P2P_OFFLOAD_RSVD_PAGE, H2C_P2PRSVDPAGE_LOC_LEN, u1H2CP2PRsvdPageParm); return ret; } u8 rtw_hal_set_p2p_wowlan_offload_cmd(_adapter *adapter) { u8 offload_cmd[H2C_P2P_OFFLOAD_LEN] = {0}; struct wifidirect_info *pwdinfo = &(adapter->wdinfo); struct P2P_WoWlan_Offload_t *p2p_wowlan_offload = (struct P2P_WoWlan_Offload_t *)offload_cmd; struct hal_ops *pHalFunc = &adapter->hal_func; u8 ret = _FAIL; _rtw_memset(p2p_wowlan_offload, 0 , sizeof(struct P2P_WoWlan_Offload_t)); RTW_INFO("%s\n", __func__); switch (pwdinfo->role) { case P2P_ROLE_DEVICE: RTW_INFO("P2P_ROLE_DEVICE\n"); p2p_wowlan_offload->role = 0; break; case P2P_ROLE_CLIENT: RTW_INFO("P2P_ROLE_CLIENT\n"); p2p_wowlan_offload->role = 1; break; case P2P_ROLE_GO: RTW_INFO("P2P_ROLE_GO\n"); p2p_wowlan_offload->role = 2; break; default: RTW_INFO("P2P_ROLE_DISABLE\n"); break; } p2p_wowlan_offload->Wps_Config[0] = pwdinfo->supported_wps_cm >> 8; p2p_wowlan_offload->Wps_Config[1] = pwdinfo->supported_wps_cm; offload_cmd = (u8 *)p2p_wowlan_offload; RTW_INFO("p2p_wowlan_offload: %x:%x:%x\n", offload_cmd[0], offload_cmd[1], offload_cmd[2]); ret = rtw_hal_fill_h2c_cmd(adapter, H2C_P2P_OFFLOAD, H2C_P2P_OFFLOAD_LEN, offload_cmd); return ret; /* FillH2CCmd8723B(adapter, H2C_8723B_P2P_OFFLOAD, sizeof(struct P2P_WoWlan_Offload_t), (u8 *)p2p_wowlan_offload); */ } #endif /* CONFIG_P2P_WOWLAN */ void rtw_hal_construct_beacon(_adapter *padapter, u8 *pframe, u32 *pLength) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u32 rate_len, pktlen; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* RTW_INFO("%s\n", __FUNCTION__); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); /* pmlmeext->mgnt_seq++; */ set_frame_sub_type(pframe, WIFI_BEACON); pframe += sizeof(struct rtw_ieee80211_hdr_3addr); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); /* timestamp will be inserted by hardware */ pframe += 8; pktlen += 8; /* beacon interval: 2 bytes */ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); pframe += 2; pktlen += 2; /* capability info: 2 bytes */ _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); pframe += 2; pktlen += 2; if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { /* RTW_INFO("ie len=%d\n", cur_network->IELength); */ pktlen += cur_network->IELength - sizeof(NDIS_802_11_FIXED_IEs); _rtw_memcpy(pframe, cur_network->IEs + sizeof(NDIS_802_11_FIXED_IEs), pktlen); goto _ConstructBeacon; } /* below for ad-hoc mode */ /* SSID */ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); /* supported rates... */ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); /* DS parameter set */ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { u32 ATIMWindow; /* IBSS Parameter Set... */ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ATIMWindow = 0; pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); } /* todo: ERP IE */ /* EXTERNDED SUPPORTED RATE */ if (rate_len > 8) pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); /* todo:HT for adhoc */ _ConstructBeacon: if ((pktlen + TXDESC_SIZE) > 512) { RTW_INFO("beacon frame too large\n"); return; } *pLength = pktlen; /* RTW_INFO("%s bcn_sz=%d\n", __FUNCTION__, pktlen); */ } static void rtw_hal_construct_PSPoll(_adapter *padapter, u8 *pframe, u32 *pLength) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u32 pktlen; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); /* RTW_INFO("%s\n", __FUNCTION__); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; /* Frame control. */ fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; SetPwrMgt(fctrl); set_frame_sub_type(pframe, WIFI_PSPOLL); /* AID. */ set_duration(pframe, (pmlmeinfo->aid | 0xc000)); /* BSSID. */ _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); /* TA. */ _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); *pLength = 16; } #ifdef DBG_FW_DEBUG_MSG_PKT void rtw_hal_construct_fw_dbg_msg_pkt( PADAPTER padapter, u8 *pframe, u32 *plength) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u32 pktlen; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_frame_sub_type(pframe, WIFI_DATA); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); *plength = pktlen; } #endif /*DBG_FW_DEBUG_MSG_PKT*/ void rtw_hal_construct_NullFunctionData( PADAPTER padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, u8 bQoS, u8 AC, u8 bEosp, u8 bForcePowerSave) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u32 pktlen; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u8 bssid[ETH_ALEN]; /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; if (bForcePowerSave) SetPwrMgt(fctrl); if (NULL == StaAddr) { _rtw_memcpy(bssid, adapter_mac_addr(padapter), ETH_ALEN); StaAddr = bssid; } switch (cur_network->network.InfrastructureMode) { case Ndis802_11Infrastructure: SetToDs(fctrl); _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); break; case Ndis802_11APMode: SetFrDs(fctrl); _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); break; case Ndis802_11IBSS: default: _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); break; } SetSeqNum(pwlanhdr, 0); set_duration(pwlanhdr, 0); if (bQoS == _TRUE) { struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr; set_frame_sub_type(pframe, WIFI_QOS_DATA_NULL); pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos *)pframe; SetPriority(&pwlanqoshdr->qc, AC); SetEOSP(&pwlanqoshdr->qc, bEosp); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); } else { set_frame_sub_type(pframe, WIFI_DATA_NULL); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); } *pLength = pktlen; } void rtw_hal_construct_ProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bHideSSID) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u8 *mac, *bssid; u32 pktlen; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); /*RTW_INFO("%s\n", __FUNCTION__);*/ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; mac = adapter_mac_addr(padapter); bssid = cur_network->MacAddress; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_frame_sub_type(fctrl, WIFI_PROBERSP); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); pframe += pktlen; if (cur_network->IELength > MAX_IE_SZ) return; _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); pframe += cur_network->IELength; pktlen += cur_network->IELength; *pLength = pktlen; } #ifdef CONFIG_WOWLAN static void rtw_hal_append_tkip_mic(PADAPTER padapter, u8 *pframe, u32 offset) { struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct rtw_ieee80211_hdr *pwlanhdr; struct mic_data micdata; struct sta_info *psta = NULL; int res = 0; u8 *payload = (u8 *)(pframe + offset); u8 mic[8]; u8 priority[4] = {0x0}; u8 null_key[16] = {0x0}; RTW_INFO("%s(): Add MIC, offset: %d\n", __func__, offset); pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(&(pmlmeinfo->network))); if (psta != NULL) { res = _rtw_memcmp(&psta->dot11tkiptxmickey.skey[0], null_key, 16); if (res == _TRUE) RTW_INFO("%s(): STA dot11tkiptxmickey==0\n", __func__); rtw_secmicsetkey(&micdata, &psta->dot11tkiptxmickey.skey[0]); } rtw_secmicappend(&micdata, pwlanhdr->addr3, 6); /* DA */ rtw_secmicappend(&micdata, pwlanhdr->addr2, 6); /* SA */ priority[0] = 0; rtw_secmicappend(&micdata, &priority[0], 4); rtw_secmicappend(&micdata, payload, 36); /* payload length = 8 + 28 */ rtw_secgetmic(&micdata, &(mic[0])); payload += 36; _rtw_memcpy(payload, &(mic[0]), 8); } /* * Description: * Construct the ARP response packet to support ARP offload. * */ static void rtw_hal_construct_ARPRsp( PADAPTER padapter, u8 *pframe, u32 *pLength, u8 *pIPAddress ) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u32 pktlen; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct security_priv *psecuritypriv = &padapter->securitypriv; static u8 ARPLLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}; u8 *pARPRspPkt = pframe; /* for TKIP Cal MIC */ u8 *payload = pframe; u8 EncryptionHeadOverhead = 0, arp_offset = 0; /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; /* ------------------------------------------------------------------------- */ /* MAC Header. */ /* ------------------------------------------------------------------------- */ SetFrameType(fctrl, WIFI_DATA); /* set_frame_sub_type(fctrl, 0); */ SetToDs(fctrl); _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_duration(pwlanhdr, 0); /* SET_80211_HDR_FRAME_CONTROL(pARPRspPkt, 0); */ /* SET_80211_HDR_TYPE_AND_SUBTYPE(pARPRspPkt, Type_Data); */ /* SET_80211_HDR_TO_DS(pARPRspPkt, 1); */ /* SET_80211_HDR_ADDRESS1(pARPRspPkt, pMgntInfo->Bssid); */ /* SET_80211_HDR_ADDRESS2(pARPRspPkt, Adapter->CurrentAddress); */ /* SET_80211_HDR_ADDRESS3(pARPRspPkt, pMgntInfo->Bssid); */ /* SET_80211_HDR_DURATION(pARPRspPkt, 0); */ /* SET_80211_HDR_FRAGMENT_SEQUENCE(pARPRspPkt, 0); */ #ifdef CONFIG_WAPI_SUPPORT *pLength = sMacHdrLng; #else *pLength = 24; #endif switch (psecuritypriv->dot11PrivacyAlgrthm) { case _WEP40_: case _WEP104_: EncryptionHeadOverhead = 4; break; case _TKIP_: EncryptionHeadOverhead = 8; break; case _AES_: EncryptionHeadOverhead = 8; break; #ifdef CONFIG_WAPI_SUPPORT case _SMS4_: EncryptionHeadOverhead = 18; break; #endif default: EncryptionHeadOverhead = 0; } if (EncryptionHeadOverhead > 0) { _rtw_memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); *pLength += EncryptionHeadOverhead; /* SET_80211_HDR_WEP(pARPRspPkt, 1); */ /* Suggested by CCW. */ SetPrivacy(fctrl); } /* ------------------------------------------------------------------------- */ /* Frame Body. */ /* ------------------------------------------------------------------------- */ arp_offset = *pLength; pARPRspPkt = (u8 *)(pframe + arp_offset); payload = pARPRspPkt; /* Get Payload pointer */ /* LLC header */ _rtw_memcpy(pARPRspPkt, ARPLLCHeader, 8); *pLength += 8; /* ARP element */ pARPRspPkt += 8; SET_ARP_PKT_HW(pARPRspPkt, 0x0100); SET_ARP_PKT_PROTOCOL(pARPRspPkt, 0x0008); /* IP protocol */ SET_ARP_PKT_HW_ADDR_LEN(pARPRspPkt, 6); SET_ARP_PKT_PROTOCOL_ADDR_LEN(pARPRspPkt, 4); SET_ARP_PKT_OPERATION(pARPRspPkt, 0x0200); /* ARP response */ SET_ARP_PKT_SENDER_MAC_ADDR(pARPRspPkt, adapter_mac_addr(padapter)); SET_ARP_PKT_SENDER_IP_ADDR(pARPRspPkt, pIPAddress); #ifdef CONFIG_ARP_KEEP_ALIVE if (!is_zero_mac_addr(pmlmepriv->gw_mac_addr)) { SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, pmlmepriv->gw_mac_addr); SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pmlmepriv->gw_ip); } else #endif { SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, get_my_bssid(&(pmlmeinfo->network))); SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pIPAddress); RTW_INFO("%s Target Mac Addr:" MAC_FMT "\n", __FUNCTION__, MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); RTW_INFO("%s Target IP Addr" IP_FMT "\n", __FUNCTION__, IP_ARG(pIPAddress)); } *pLength += 28; if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) { if (IS_HARDWARE_TYPE_8188E(padapter) || IS_HARDWARE_TYPE_8812(padapter)) { rtw_hal_append_tkip_mic(padapter, pframe, arp_offset); } *pLength += 8; } } #ifdef CONFIG_IPV6 /* * Description: Neighbor Discovery Offload. */ static void rtw_hal_construct_na_message(_adapter *padapter, u8 *pframe, u32 *pLength) { struct rtw_ieee80211_hdr *pwlanhdr = NULL; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct security_priv *psecuritypriv = &padapter->securitypriv; u32 pktlen = 0; u16 *fctrl = NULL; u8 ns_hdr[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x86, 0xDD}; u8 ipv6_info[4] = {0x60, 0x00, 0x00, 0x00}; u8 ipv6_contx[4] = {0x00, 0x20, 0x3a, 0xff}; u8 icmpv6_hdr[8] = {0x88, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00}; u8 val8 = 0; u8 *p_na_msg = pframe; /* for TKIP Cal MIC */ u8 *payload = pframe; u8 EncryptionHeadOverhead = 0, na_msg_offset = 0; /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; /* ------------------------------------------------------------------------- */ /* MAC Header. */ /* ------------------------------------------------------------------------- */ SetFrameType(fctrl, WIFI_DATA); SetToDs(fctrl); _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_duration(pwlanhdr, 0); #ifdef CONFIG_WAPI_SUPPORT *pLength = sMacHdrLng; #else *pLength = 24; #endif switch (psecuritypriv->dot11PrivacyAlgrthm) { case _WEP40_: case _WEP104_: EncryptionHeadOverhead = 4; break; case _TKIP_: EncryptionHeadOverhead = 8; break; case _AES_: EncryptionHeadOverhead = 8; break; #ifdef CONFIG_WAPI_SUPPORT case _SMS4_: EncryptionHeadOverhead = 18; break; #endif default: EncryptionHeadOverhead = 0; } if (EncryptionHeadOverhead > 0) { _rtw_memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); *pLength += EncryptionHeadOverhead; /* SET_80211_HDR_WEP(pARPRspPkt, 1); */ /* Suggested by CCW. */ SetPrivacy(fctrl); } /* ------------------------------------------------------------------------- */ /* Frame Body. */ /* ------------------------------------------------------------------------- */ na_msg_offset = *pLength; p_na_msg = (u8 *)(pframe + na_msg_offset); payload = p_na_msg; /* Get Payload pointer */ /* LLC header */ val8 = sizeof(ns_hdr); _rtw_memcpy(p_na_msg, ns_hdr, val8); *pLength += val8; p_na_msg += val8; /* IPv6 Header */ /* 1 . Information (4 bytes): 0x60 0x00 0x00 0x00 */ val8 = sizeof(ipv6_info); _rtw_memcpy(p_na_msg, ipv6_info, val8); *pLength += val8; p_na_msg += val8; /* 2 . playload : 0x00 0x20 , NextProt : 0x3a (ICMPv6) HopLim : 0xff */ val8 = sizeof(ipv6_contx); _rtw_memcpy(p_na_msg, ipv6_contx, val8); *pLength += val8; p_na_msg += val8; /* 3 . SA : 16 bytes , DA : 16 bytes ( Fw will filled ) */ _rtw_memset(&(p_na_msg[*pLength]), 0, 32); *pLength += 32; p_na_msg += 32; /* ICMPv6 */ /* 1. Type : 0x88 (NA) * 2. Code : 0x00 * 3. ChechSum : 0x00 0x00 (RSvd) * 4. NAFlag: 0x60 0x00 0x00 0x00 ( Solicited , Override) */ val8 = sizeof(icmpv6_hdr); _rtw_memcpy(p_na_msg, icmpv6_hdr, val8); *pLength += val8; p_na_msg += val8; /* TA: 16 bytes*/ _rtw_memset(&(p_na_msg[*pLength]), 0, 16); *pLength += 16; p_na_msg += 16; /* ICMPv6 Target Link Layer Address */ p_na_msg[0] = 0x02; /* type */ p_na_msg[1] = 0x01; /* len 1 unit of 8 octes */ *pLength += 2; p_na_msg += 2; _rtw_memset(&(p_na_msg[*pLength]), 0, 6); *pLength += 6; p_na_msg += 6; if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) { if (IS_HARDWARE_TYPE_8188E(padapter) || IS_HARDWARE_TYPE_8812(padapter)) { rtw_hal_append_tkip_mic(padapter, pframe, na_msg_offset); } *pLength += 8; } } /* * Description: Neighbor Discovery Protocol Information. */ static void rtw_hal_construct_ndp_info(_adapter *padapter, u8 *pframe, u32 *pLength) { struct mlme_ext_priv *pmlmeext = NULL; struct mlme_ext_info *pmlmeinfo = NULL; struct rtw_ndp_info ndp_info; u8 *pndp_info = pframe; u8 len = sizeof(struct rtw_ndp_info); RTW_INFO("%s: len: %d\n", __func__, len); pmlmeext = &padapter->mlmeextpriv; pmlmeinfo = &pmlmeext->mlmext_info; _rtw_memset(pframe, 0, len); _rtw_memset(&ndp_info, 0, len); ndp_info.enable = 1; ndp_info.check_remote_ip = 0; ndp_info.num_of_target_ip = 1; _rtw_memcpy(&ndp_info.target_link_addr, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(&ndp_info.target_ipv6_addr, pmlmeinfo->ip6_addr, RTW_IPv6_ADDR_LEN); _rtw_memcpy(pndp_info, &ndp_info, len); } #endif /* CONFIG_IPV6 */ #ifdef CONFIG_PNO_SUPPORT static void rtw_hal_construct_ProbeReq(_adapter *padapter, u8 *pframe, u32 *pLength, pno_ssid_t *ssid) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u32 pktlen; unsigned char *mac; unsigned char bssrate[NumRates]; struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); int bssrate_len = 0; u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; mac = adapter_mac_addr(padapter); fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_frame_sub_type(pframe, WIFI_PROBEREQ); pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); pframe += pktlen; if (ssid == NULL) pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &pktlen); else { /* RTW_INFO("%s len:%d\n", ssid->SSID, ssid->SSID_len); */ pframe = rtw_set_ie(pframe, _SSID_IE_, ssid->SSID_len, ssid->SSID, &pktlen); } get_rate_set(padapter, bssrate, &bssrate_len); if (bssrate_len > 8) { pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &pktlen); pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &pktlen); } else pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &pktlen); *pLength = pktlen; } static void rtw_hal_construct_PNO_info(_adapter *padapter, u8 *pframe, u32 *pLength) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); int i; u8 *pPnoInfoPkt = pframe; pPnoInfoPkt = (u8 *)(pframe + *pLength); _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_num, 1); pPnoInfoPkt += 1; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->hidden_ssid_num, 1); pPnoInfoPkt += 3; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_period, 1); pPnoInfoPkt += 4; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_iterations, 4); pPnoInfoPkt += 4; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->slow_scan_period, 4); pPnoInfoPkt += 4; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_length, MAX_PNO_LIST_COUNT); pPnoInfoPkt += MAX_PNO_LIST_COUNT; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_cipher_info, MAX_PNO_LIST_COUNT); pPnoInfoPkt += MAX_PNO_LIST_COUNT; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_channel_info, MAX_PNO_LIST_COUNT); pPnoInfoPkt += MAX_PNO_LIST_COUNT; _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->loc_probe_req, MAX_HIDDEN_AP); pPnoInfoPkt += MAX_HIDDEN_AP; /* SSID is located at 128th Byte in NLO info Page */ *pLength += 128; pPnoInfoPkt = pframe + 128; for (i = 0; i < pwrctl->pnlo_info->ssid_num ; i++) { _rtw_memcpy(pPnoInfoPkt, &pwrctl->pno_ssid_list->node[i].SSID, pwrctl->pnlo_info->ssid_length[i]); *pLength += WLAN_SSID_MAXLEN; pPnoInfoPkt += WLAN_SSID_MAXLEN; } } static void rtw_hal_construct_ssid_list(_adapter *padapter, u8 *pframe, u32 *pLength) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); u8 *pSSIDListPkt = pframe; int i; pSSIDListPkt = (u8 *)(pframe + *pLength); for (i = 0; i < pwrctl->pnlo_info->ssid_num ; i++) { _rtw_memcpy(pSSIDListPkt, &pwrctl->pno_ssid_list->node[i].SSID, pwrctl->pnlo_info->ssid_length[i]); *pLength += WLAN_SSID_MAXLEN; pSSIDListPkt += WLAN_SSID_MAXLEN; } } static void rtw_hal_construct_scan_info(_adapter *padapter, u8 *pframe, u32 *pLength) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); u8 *pScanInfoPkt = pframe; int i; pScanInfoPkt = (u8 *)(pframe + *pLength); _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->channel_num, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_ch, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_bw, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_40_offset, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_80_offset, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->periodScan, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->period_scan_time, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->enableRFE, 1); *pLength += 1; pScanInfoPkt += 1; _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->rfe_type, 8); *pLength += 8; pScanInfoPkt += 8; for (i = 0 ; i < MAX_SCAN_LIST_COUNT ; i++) { _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->ssid_channel_info[i], 4); *pLength += 4; pScanInfoPkt += 4; } } #endif /* CONFIG_PNO_SUPPORT */ #ifdef CONFIG_GTK_OL static void rtw_hal_construct_GTKRsp( PADAPTER padapter, u8 *pframe, u32 *pLength ) { struct rtw_ieee80211_hdr *pwlanhdr; u16 *fctrl; u32 pktlen; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct security_priv *psecuritypriv = &padapter->securitypriv; static u8 LLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E}; static u8 GTKbody_a[11] = {0x01, 0x03, 0x00, 0x5F, 0x02, 0x03, 0x12, 0x00, 0x10, 0x42, 0x0B}; u8 *pGTKRspPkt = pframe; u8 EncryptionHeadOverhead = 0; /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; /* ------------------------------------------------------------------------- */ /* MAC Header. */ /* ------------------------------------------------------------------------- */ SetFrameType(fctrl, WIFI_DATA); /* set_frame_sub_type(fctrl, 0); */ SetToDs(fctrl); _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); SetSeqNum(pwlanhdr, 0); set_duration(pwlanhdr, 0); #ifdef CONFIG_WAPI_SUPPORT *pLength = sMacHdrLng; #else *pLength = 24; #endif /* CONFIG_WAPI_SUPPORT */ /* ------------------------------------------------------------------------- */ /* Security Header: leave space for it if necessary. */ /* ------------------------------------------------------------------------- */ switch (psecuritypriv->dot11PrivacyAlgrthm) { case _WEP40_: case _WEP104_: EncryptionHeadOverhead = 4; break; case _TKIP_: EncryptionHeadOverhead = 8; break; case _AES_: EncryptionHeadOverhead = 8; break; #ifdef CONFIG_WAPI_SUPPORT case _SMS4_: EncryptionHeadOverhead = 18; break; #endif /* CONFIG_WAPI_SUPPORT */ default: EncryptionHeadOverhead = 0; } if (EncryptionHeadOverhead > 0) { _rtw_memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); *pLength += EncryptionHeadOverhead; /* SET_80211_HDR_WEP(pGTKRspPkt, 1); */ /* Suggested by CCW. */ /* GTK's privacy bit is done by FW */ /* SetPrivacy(fctrl); */ } /* ------------------------------------------------------------------------- */ /* Frame Body. */ /* ------------------------------------------------------------------------- */ pGTKRspPkt = (u8 *)(pframe + *pLength); /* LLC header */ _rtw_memcpy(pGTKRspPkt, LLCHeader, 8); *pLength += 8; /* GTK element */ pGTKRspPkt += 8; /* GTK frame body after LLC, part 1 */ /* TKIP key_length = 32, AES key_length = 16 */ if (psecuritypriv->dot118021XGrpPrivacy == _TKIP_) GTKbody_a[8] = 0x20; /* GTK frame body after LLC, part 1 */ _rtw_memcpy(pGTKRspPkt, GTKbody_a, 11); *pLength += 11; pGTKRspPkt += 11; /* GTK frame body after LLC, part 2 */ _rtw_memset(&(pframe[*pLength]), 0, 88); *pLength += 88; pGTKRspPkt += 88; if (psecuritypriv->dot118021XGrpPrivacy == _TKIP_) *pLength += 8; } #endif /* CONFIG_GTK_OL */ #define PN_2_CCMPH(ch,key_id) ((ch) & 0x000000000000ffff) \ | (((ch) & 0x0000ffffffff0000) << 16) \ | (((key_id) << 30)) \ | BIT(29) static void rtw_hal_construct_remote_control_info(_adapter *adapter, u8 *pframe, u32 *pLength) { struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct sta_priv *pstapriv = &adapter->stapriv; struct security_priv *psecuritypriv = &adapter->securitypriv; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sta_info *psta; struct stainfo_rxcache *prxcache; u8 cur_dot11rxiv[8], id = 0, tid_id = 0, i = 0; size_t sz = 0, total = 0; u64 ccmp_hdr = 0, tmp_key = 0; psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); if (psta == NULL) { rtw_warn_on(1); return; } prxcache = &psta->sta_recvpriv.rxcache; sz = sizeof(cur_dot11rxiv); /* 3 SEC IV * 1 page */ rtw_get_sec_iv(adapter, cur_dot11rxiv, get_my_bssid(&pmlmeinfo->network)); _rtw_memcpy(pframe, cur_dot11rxiv, sz); *pLength += sz; pframe += sz; _rtw_memset(&cur_dot11rxiv, 0, sz); if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { id = psecuritypriv->dot118021XGrpKeyid; tid_id = prxcache->last_tid; REMOTE_INFO_CTRL_SET_VALD_EN(cur_dot11rxiv, 0xdd); REMOTE_INFO_CTRL_SET_PTK_EN(cur_dot11rxiv, 1); REMOTE_INFO_CTRL_SET_GTK_EN(cur_dot11rxiv, 1); REMOTE_INFO_CTRL_SET_GTK_IDX(cur_dot11rxiv, id); _rtw_memcpy(pframe, cur_dot11rxiv, sz); *pLength += sz; pframe += sz; _rtw_memcpy(pframe, prxcache->iv[tid_id], sz); *pLength += sz; pframe += sz; total = sizeof(psecuritypriv->iv_seq); total /= sizeof(psecuritypriv->iv_seq[0]); for (i = 0 ; i < total ; i ++) { ccmp_hdr = le64_to_cpu(*(u64*)psecuritypriv->iv_seq[i]); _rtw_memset(&cur_dot11rxiv, 0, sz); if (ccmp_hdr != 0) { tmp_key = i; ccmp_hdr = PN_2_CCMPH(ccmp_hdr, tmp_key); *(u64*)cur_dot11rxiv = cpu_to_le64(ccmp_hdr); _rtw_memcpy(pframe, cur_dot11rxiv, sz); } *pLength += sz; pframe += sz; } } } /*#define DBG_RSVD_PAGE_CFG*/ #ifdef DBG_RSVD_PAGE_CFG #define RSVD_PAGE_CFG(ops, v1, v2, v3) \ RTW_INFO("=== [RSVD][%s]-NeedPage:%d, TotalPageNum:%d TotalPacketLen:%d ===\n", \ ops, v1, v2, v3) #endif void rtw_hal_set_wow_fw_rsvd_page(_adapter *adapter, u8 *pframe, u16 index, u8 tx_desc, u32 page_size, u8 *page_num, u32 *total_pkt_len, RSVDPAGE_LOC *rsvd_page_loc) { struct security_priv *psecuritypriv = &adapter->securitypriv; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct mlme_ext_priv *pmlmeext; struct mlme_ext_info *pmlmeinfo; u32 ARPLength = 0, GTKLength = 0, PNOLength = 0, ScanInfoLength = 0; u32 SSIDLegnth = 0, ProbeReqLength = 0, ns_len = 0, rc_len = 0; u8 CurtPktPageNum = 0; #ifdef CONFIG_GTK_OL struct sta_priv *pstapriv = &adapter->stapriv; struct sta_info *psta; struct security_priv *psecpriv = &adapter->securitypriv; u8 kek[RTW_KEK_LEN]; u8 kck[RTW_KCK_LEN]; #endif /* CONFIG_GTK_OL */ #ifdef CONFIG_PNO_SUPPORT int pno_index; u8 ssid_num; #endif /* CONFIG_PNO_SUPPORT */ pmlmeext = &adapter->mlmeextpriv; pmlmeinfo = &pmlmeext->mlmext_info; if (pwrctl->wowlan_pno_enable == _FALSE) { /* ARP RSP * 1 page */ rsvd_page_loc->LocArpRsp = *page_num; RTW_INFO("LocArpRsp: %d\n", rsvd_page_loc->LocArpRsp); rtw_hal_construct_ARPRsp(adapter, &pframe[index], &ARPLength, pmlmeinfo->ip_addr); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], ARPLength, _FALSE, _FALSE, _TRUE); CurtPktPageNum = (u8)PageNum(tx_desc + ARPLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-ARPRsp", CurtPktPageNum, *page_num, 0); #endif #ifdef CONFIG_IPV6 /* 2 NS offload and NDP Info*/ if (pwrctl->wowlan_ns_offload_en == _TRUE) { rsvd_page_loc->LocNbrAdv = *page_num; RTW_INFO("LocNbrAdv: %d\n", rsvd_page_loc->LocNbrAdv); rtw_hal_construct_na_message(adapter, &pframe[index], &ns_len); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], ns_len, _FALSE, _FALSE, _TRUE); CurtPktPageNum = (u8)PageNum(tx_desc + ns_len, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-NbrAdv", CurtPktPageNum, *page_num, 0); #endif rsvd_page_loc->LocNDPInfo = *page_num; RTW_INFO("LocNDPInfo: %d\n", rsvd_page_loc->LocNDPInfo); rtw_hal_construct_ndp_info(adapter, &pframe[index - tx_desc], &ns_len); CurtPktPageNum = (u8)PageNum(tx_desc + ns_len, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-NDPInfo", CurtPktPageNum, *page_num, 0); #endif } #endif /*CONFIG_IPV6*/ /* 3 Remote Control Info. * 1 page */ rsvd_page_loc->LocRemoteCtrlInfo = *page_num; RTW_INFO("LocRemoteCtrlInfo: %d\n", rsvd_page_loc->LocRemoteCtrlInfo); rtw_hal_construct_remote_control_info(adapter, &pframe[index - tx_desc], &rc_len); CurtPktPageNum = (u8)PageNum(rc_len, page_size); *page_num += CurtPktPageNum; *total_pkt_len = index + rc_len; #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-RCI", CurtPktPageNum, *page_num, *total_pkt_len); #endif #ifdef CONFIG_GTK_OL index += (CurtPktPageNum * page_size); /* if the ap staion info. exists, get the kek, kck from staion info. */ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); if (psta == NULL) { _rtw_memset(kek, 0, RTW_KEK_LEN); _rtw_memset(kck, 0, RTW_KCK_LEN); RTW_INFO("%s, KEK, KCK download rsvd page all zero\n", __func__); } else { _rtw_memcpy(kek, psta->kek, RTW_KEK_LEN); _rtw_memcpy(kck, psta->kck, RTW_KCK_LEN); } /* 3 KEK, KCK */ rsvd_page_loc->LocGTKInfo = *page_num; RTW_INFO("LocGTKInfo: %d\n", rsvd_page_loc->LocGTKInfo); if (IS_HARDWARE_TYPE_8188E(adapter) || IS_HARDWARE_TYPE_8812(adapter)) { struct security_priv *psecpriv = NULL; psecpriv = &adapter->securitypriv; _rtw_memcpy(pframe + index - tx_desc, &psecpriv->dot11PrivacyAlgrthm, 1); _rtw_memcpy(pframe + index - tx_desc + 1, &psecpriv->dot118021XGrpPrivacy, 1); _rtw_memcpy(pframe + index - tx_desc + 2, kck, RTW_KCK_LEN); _rtw_memcpy(pframe + index - tx_desc + 2 + RTW_KCK_LEN, kek, RTW_KEK_LEN); CurtPktPageNum = (u8)PageNum(tx_desc + 2 + RTW_KCK_LEN + RTW_KEK_LEN, page_size); } else { _rtw_memcpy(pframe + index - tx_desc, kck, RTW_KCK_LEN); _rtw_memcpy(pframe + index - tx_desc + RTW_KCK_LEN, kek, RTW_KEK_LEN); GTKLength = tx_desc + RTW_KCK_LEN + RTW_KEK_LEN; if (psta != NULL && psecuritypriv->dot118021XGrpPrivacy == _TKIP_) { _rtw_memcpy(pframe + index - tx_desc + 56, &psta->dot11tkiptxmickey, RTW_TKIP_MIC_LEN); GTKLength += RTW_TKIP_MIC_LEN; } CurtPktPageNum = (u8)PageNum(GTKLength, page_size); } #if 0 { int i; printk("\ntoFW KCK: "); for (i = 0; i < 16; i++) printk(" %02x ", kck[i]); printk("\ntoFW KEK: "); for (i = 0; i < 16; i++) printk(" %02x ", kek[i]); printk("\n"); } RTW_INFO("%s(): HW_VAR_SET_TX_CMD: KEK KCK %p %d\n", __FUNCTION__, &pframe[index - tx_desc], (tx_desc + RTW_KCK_LEN + RTW_KEK_LEN)); #endif *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-GTKInfo", CurtPktPageNum, *page_num, 0); #endif /* 3 GTK Response */ rsvd_page_loc->LocGTKRsp = *page_num; RTW_INFO("LocGTKRsp: %d\n", rsvd_page_loc->LocGTKRsp); rtw_hal_construct_GTKRsp(adapter, &pframe[index], >KLength); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], GTKLength, _FALSE, _FALSE, _TRUE); #if 0 { int gj; printk("123GTK pkt=>\n"); for (gj = 0; gj < GTKLength + tx_desc; gj++) { printk(" %02x ", pframe[index - tx_desc + gj]); if ((gj + 1) % 16 == 0) printk("\n"); } printk(" <=end\n"); } RTW_INFO("%s(): HW_VAR_SET_TX_CMD: GTK RSP %p %d\n", __FUNCTION__, &pframe[index - tx_desc], (tx_desc + GTKLength)); #endif CurtPktPageNum = (u8)PageNum(tx_desc + GTKLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-GTKRsp", CurtPktPageNum, *page_num, 0); #endif /* below page is empty for GTK extension memory */ /* 3(11) GTK EXT MEM */ rsvd_page_loc->LocGTKEXTMEM = *page_num; RTW_INFO("LocGTKEXTMEM: %d\n", rsvd_page_loc->LocGTKEXTMEM); CurtPktPageNum = 2; if (page_size >= 256) CurtPktPageNum = 1; *page_num += CurtPktPageNum; /* extension memory for FW */ *total_pkt_len = index + (page_size * CurtPktPageNum); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-GTKEXTMEM", CurtPktPageNum, *page_num, *total_pkt_len); #endif #endif /* CONFIG_GTK_OL */ index += (CurtPktPageNum * page_size); /*Reserve 1 page for AOAC report*/ rsvd_page_loc->LocAOACReport = *page_num; RTW_INFO("LocAOACReport: %d\n", rsvd_page_loc->LocAOACReport); *page_num += 1; *total_pkt_len = index + (page_size * 1); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-AOAC", 1, *page_num, *total_pkt_len); #endif } else { #ifdef CONFIG_PNO_SUPPORT if (pwrctl->wowlan_in_resume == _FALSE && pwrctl->pno_inited == _TRUE) { /* Broadcast Probe Request */ rsvd_page_loc->LocProbePacket = *page_num; RTW_INFO("loc_probe_req: %d\n", rsvd_page_loc->LocProbePacket); rtw_hal_construct_ProbeReq( adapter, &pframe[index], &ProbeReqLength, NULL); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], ProbeReqLength, _FALSE, _FALSE, _FALSE); CurtPktPageNum = (u8)PageNum(tx_desc + ProbeReqLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-ProbeReq", CurtPktPageNum, *page_num, 0); #endif /* Hidden SSID Probe Request */ ssid_num = pwrctl->pnlo_info->hidden_ssid_num; for (pno_index = 0 ; pno_index < ssid_num ; pno_index++) { pwrctl->pnlo_info->loc_probe_req[pno_index] = *page_num; rtw_hal_construct_ProbeReq( adapter, &pframe[index], &ProbeReqLength, &pwrctl->pno_ssid_list->node[pno_index]); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], ProbeReqLength, _FALSE, _FALSE, _FALSE); CurtPktPageNum = (u8)PageNum(tx_desc + ProbeReqLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-ProbeReq", CurtPktPageNum, *page_num, 0); #endif } /* PNO INFO Page */ rsvd_page_loc->LocPNOInfo = *page_num; RTW_INFO("LocPNOInfo: %d\n", rsvd_page_loc->LocPNOInfo); rtw_hal_construct_PNO_info(adapter, &pframe[index - tx_desc], &PNOLength); CurtPktPageNum = (u8)PageNum(PNOLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-PNOInfo", CurtPktPageNum, *page_num, 0); #endif /* Scan Info Page */ rsvd_page_loc->LocScanInfo = *page_num; RTW_INFO("LocScanInfo: %d\n", rsvd_page_loc->LocScanInfo); rtw_hal_construct_scan_info(adapter, &pframe[index - tx_desc], &ScanInfoLength); CurtPktPageNum = (u8)PageNum(ScanInfoLength, page_size); *page_num += CurtPktPageNum; *total_pkt_len = index + ScanInfoLength; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-ScanInfo", CurtPktPageNum, *page_num, *total_pkt_len); #endif } #endif /* CONFIG_PNO_SUPPORT */ } } static void rtw_hal_gate_bb(_adapter *adapter, bool stop) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); u8 i = 0, val8 = 0, empty = _FAIL; u16 val16 = 0; if (stop) { /* checking TX queue status */ for (i = 0 ; i < 5 ; i++) { rtw_hal_get_hwreg(adapter, HW_VAR_CHK_MGQ_CPU_EMPTY, &empty); if (empty) { break; } else { RTW_WARN("%s: MGQ_CPU is busy(%d)!\n", __func__, i); rtw_mdelay_os(10); } } if (val8 == 5) RTW_ERR("%s: Polling MGQ_CPU empty fail!\n", __func__); /* Pause TX*/ pwrpriv->wowlan_txpause_status = rtw_read8(adapter, REG_TXPAUSE); rtw_write8(adapter, REG_TXPAUSE, 0xff); val8 = rtw_read8(adapter, REG_SYS_FUNC_EN); val8 &= ~BIT(0); rtw_write8(adapter, REG_SYS_FUNC_EN, val8); RTW_INFO("%s: BB gated: 0x%02x, store TXPAUSE: %02x\n", __func__, rtw_read8(adapter, REG_SYS_FUNC_EN), pwrpriv->wowlan_txpause_status); } else { val8 = rtw_read8(adapter, REG_SYS_FUNC_EN); val8 |= BIT(0); rtw_write8(adapter, REG_SYS_FUNC_EN, val8); RTW_INFO("%s: BB release: 0x%02x, recover TXPAUSE:%02x\n", __func__, rtw_read8(adapter, REG_SYS_FUNC_EN), pwrpriv->wowlan_txpause_status); /* release TX*/ rtw_write8(adapter, REG_TXPAUSE, pwrpriv->wowlan_txpause_status); } } static void rtw_hal_reset_mac_rx(_adapter *adapter) { u8 val8 = 0; /* Set REG_CR bit1, bit3, bit7 to 0*/ val8 = rtw_read8(adapter, REG_CR); val8 &= 0x75; rtw_write8(adapter, REG_CR, val8); val8 = rtw_read8(adapter, REG_CR); /* Set REG_CR bit1, bit3, bit7 to 1*/ val8 |= 0x8a; rtw_write8(adapter, REG_CR, val8); RTW_INFO("0x%04x: %02x\n", REG_CR, rtw_read8(adapter, REG_CR)); } static u8 rtw_hal_wow_pattern_generate(_adapter *adapter, u8 idx, struct rtl_wow_pattern *pwow_pattern) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); u8 *pattern; u8 len = 0; u8 *mask; u8 mask_hw[MAX_WKFM_SIZE] = {0}; u8 content[MAX_WKFM_PATTERN_SIZE] = {0}; u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u8 multicast_addr1[2] = {0x33, 0x33}; u8 multicast_addr2[3] = {0x01, 0x00, 0x5e}; u8 mask_len = 0; u8 mac_addr[ETH_ALEN] = {0}; u16 count = 0; int i, j; if (pwrctl->wowlan_pattern_idx > MAX_WKFM_CAM_NUM) { RTW_INFO("%s pattern_idx is more than MAX_FMC_NUM: %d\n", __func__, MAX_WKFM_CAM_NUM); return _FAIL; } pattern = pwrctl->patterns[idx].content; len = pwrctl->patterns[idx].len; mask = pwrctl->patterns[idx].mask; _rtw_memcpy(mac_addr, adapter_mac_addr(adapter), ETH_ALEN); _rtw_memset(pwow_pattern, 0, sizeof(struct rtl_wow_pattern)); mask_len = DIV_ROUND_UP(len, 8); /* 1. setup A1 table */ if (memcmp(pattern, broadcast_addr, ETH_ALEN) == 0) pwow_pattern->type = PATTERN_BROADCAST; else if (memcmp(pattern, multicast_addr1, 2) == 0) pwow_pattern->type = PATTERN_MULTICAST; else if (memcmp(pattern, multicast_addr2, 3) == 0) pwow_pattern->type = PATTERN_MULTICAST; else if (memcmp(pattern, mac_addr, ETH_ALEN) == 0) pwow_pattern->type = PATTERN_UNICAST; else pwow_pattern->type = PATTERN_INVALID; /* translate mask from os to mask for hw */ /****************************************************************************** * pattern from OS uses 'ethenet frame', like this: | 6 | 6 | 2 | 20 | Variable | 4 | |--------+--------+------+-----------+------------+-----| | 802.3 Mac Header | IP Header | TCP Packet | FCS | | DA | SA | Type | * BUT, packet catched by our HW is in '802.11 frame', begin from LLC, | 24 or 30 | 6 | 2 | 20 | Variable | 4 | |-------------------+--------+------+-----------+------------+-----| | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | | Others | Tpye | * Therefore, we need translate mask_from_OS to mask_to_hw. * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, * because new mask[0~5] means 'SA', but our HW packet begins from LLC, * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. ******************************************************************************/ /* Shift 6 bits */ for (i = 0; i < mask_len - 1; i++) { mask_hw[i] = mask[i] >> 6; mask_hw[i] |= (mask[i + 1] & 0x3F) << 2; } mask_hw[i] = (mask[i] >> 6) & 0x3F; /* Set bit 0-5 to zero */ mask_hw[0] &= 0xC0; for (i = 0; i < (MAX_WKFM_SIZE / 4); i++) { pwow_pattern->mask[i] = mask_hw[i * 4]; pwow_pattern->mask[i] |= (mask_hw[i * 4 + 1] << 8); pwow_pattern->mask[i] |= (mask_hw[i * 4 + 2] << 16); pwow_pattern->mask[i] |= (mask_hw[i * 4 + 3] << 24); } /* To get the wake up pattern from the mask. * We do not count first 12 bits which means * DA[6] and SA[6] in the pattern to match HW design. */ count = 0; for (i = 12; i < len; i++) { if ((mask[i / 8] >> (i % 8)) & 0x01) { content[count] = pattern[i]; count++; } } pwow_pattern->crc = rtw_calc_crc(content, count); if (pwow_pattern->crc != 0) { if (pwow_pattern->type == PATTERN_INVALID) pwow_pattern->type = PATTERN_VALID; } return _SUCCESS; } #ifndef CONFIG_WOW_PATTERN_HW_CAM static void rtw_hal_set_wow_rxff_boundary(_adapter *adapter, bool wow_mode) { u8 val8 = 0; u16 rxff_bndy = 0; u32 rx_dma_buff_sz = 0; val8 = rtw_read8(adapter, REG_FIFOPAGE + 3); if (val8 != 0) RTW_INFO("%s:[%04x]some PKTs in TXPKTBUF\n", __func__, (REG_FIFOPAGE + 3)); rtw_hal_reset_mac_rx(adapter); if (wow_mode) { rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ_WOW, (u8 *)&rx_dma_buff_sz); rxff_bndy = rx_dma_buff_sz - 1; rtw_write16(adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); RTW_INFO("%s: wow mode, 0x%04x: 0x%04x\n", __func__, REG_TRXFF_BNDY + 2, rtw_read16(adapter, (REG_TRXFF_BNDY + 2))); } else { rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ, (u8 *)&rx_dma_buff_sz); rxff_bndy = rx_dma_buff_sz - 1; rtw_write16(adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); RTW_INFO("%s: normal mode, 0x%04x: 0x%04x\n", __func__, REG_TRXFF_BNDY + 2, rtw_read16(adapter, (REG_TRXFF_BNDY + 2))); } } bool rtw_read_from_frame_mask(_adapter *adapter, u8 idx) { u32 data_l = 0, data_h = 0, rx_dma_buff_sz = 0, page_sz = 0; u16 offset, rx_buf_ptr = 0; u16 cam_start_offset = 0; u16 ctrl_l = 0, ctrl_h = 0; u8 count = 0, tmp = 0; int i = 0; bool res = _TRUE; if (idx > MAX_WKFM_CAM_NUM) { RTW_INFO("[Error]: %s, pattern index is out of range\n", __func__); return _FALSE; } rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ_WOW, (u8 *)&rx_dma_buff_sz); if (rx_dma_buff_sz == 0) { RTW_INFO("[Error]: %s, rx_dma_buff_sz is 0!!\n", __func__); return _FALSE; } rtw_hal_get_def_var(adapter, HAL_DEF_RX_PAGE_SIZE, (u8 *)&page_sz); if (page_sz == 0) { RTW_INFO("[Error]: %s, page_sz is 0!!\n", __func__); return _FALSE; } offset = (u16)PageNum(rx_dma_buff_sz, page_sz); cam_start_offset = offset * page_sz; ctrl_l = 0x0; ctrl_h = 0x0; /* Enable RX packet buffer access */ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, RXPKT_BUF_SELECT); /* Read the WKFM CAM */ for (i = 0; i < (WKFMCAM_ADDR_NUM / 2); i++) { /* * Set Rx packet buffer offset. * RxBufer pointer increases 1, we can access 8 bytes in Rx packet buffer. * CAM start offset (unit: 1 byte) = Index*WKFMCAM_SIZE * RxBufer pointer addr = (CAM start offset + per entry offset of a WKFMCAM)/8 * * Index: The index of the wake up frame mask * * WKFMCAM_SIZE: the total size of one WKFM CAM * * per entry offset of a WKFM CAM: Addr i * 4 bytes */ rx_buf_ptr = (cam_start_offset + idx * WKFMCAM_SIZE + i * 8) >> 3; rtw_write16(adapter, REG_PKTBUF_DBG_CTRL, rx_buf_ptr); rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_l); data_l = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L); data_h = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H); RTW_INFO("[%d]: %08x %08x\n", i, data_h, data_l); count = 0; do { tmp = rtw_read8(adapter, REG_RXPKTBUF_CTRL); rtw_udelay_os(2); count++; } while (!tmp && count < 100); if (count >= 100) { RTW_INFO("%s count:%d\n", __func__, count); res = _FALSE; } } /* Disable RX packet buffer access */ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); return res; } bool rtw_write_to_frame_mask(_adapter *adapter, u8 idx, struct rtl_wow_pattern *context) { u32 data = 0, rx_dma_buff_sz = 0, page_sz = 0; u16 offset, rx_buf_ptr = 0; u16 cam_start_offset = 0; u16 ctrl_l = 0, ctrl_h = 0; u8 count = 0, tmp = 0; int res = 0, i = 0; if (idx > MAX_WKFM_CAM_NUM) { RTW_INFO("[Error]: %s, pattern index is out of range\n", __func__); return _FALSE; } rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ_WOW, (u8 *)&rx_dma_buff_sz); if (rx_dma_buff_sz == 0) { RTW_INFO("[Error]: %s, rx_dma_buff_sz is 0!!\n", __func__); return _FALSE; } rtw_hal_get_def_var(adapter, HAL_DEF_RX_PAGE_SIZE, (u8 *)&page_sz); if (page_sz == 0) { RTW_INFO("[Error]: %s, page_sz is 0!!\n", __func__); return _FALSE; } offset = (u16)PageNum(rx_dma_buff_sz, page_sz); cam_start_offset = offset * page_sz; if (IS_HARDWARE_TYPE_8188E(adapter)) { ctrl_l = 0x0001; ctrl_h = 0x0001; } else { ctrl_l = 0x0f01; ctrl_h = 0xf001; } /* Enable RX packet buffer access */ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, RXPKT_BUF_SELECT); /* Write the WKFM CAM */ for (i = 0; i < WKFMCAM_ADDR_NUM; i++) { /* * Set Rx packet buffer offset. * RxBufer pointer increases 1, we can access 8 bytes in Rx packet buffer. * CAM start offset (unit: 1 byte) = Index*WKFMCAM_SIZE * RxBufer pointer addr = (CAM start offset + per entry offset of a WKFMCAM)/8 * * Index: The index of the wake up frame mask * * WKFMCAM_SIZE: the total size of one WKFM CAM * * per entry offset of a WKFM CAM: Addr i * 4 bytes */ rx_buf_ptr = (cam_start_offset + idx * WKFMCAM_SIZE + i * 4) >> 3; rtw_write16(adapter, REG_PKTBUF_DBG_CTRL, rx_buf_ptr); if (i == 0) { if (context->type == PATTERN_VALID) data = BIT(31); else if (context->type == PATTERN_BROADCAST) data = BIT(31) | BIT(26); else if (context->type == PATTERN_MULTICAST) data = BIT(31) | BIT(25); else if (context->type == PATTERN_UNICAST) data = BIT(31) | BIT(24); if (context->crc != 0) data |= context->crc; rtw_write32(adapter, REG_PKTBUF_DBG_DATA_L, data); rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_l); } else if (i == 1) { data = 0; rtw_write32(adapter, REG_PKTBUF_DBG_DATA_H, data); rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_h); } else if (i == 2 || i == 4) { data = context->mask[i - 2]; rtw_write32(adapter, REG_PKTBUF_DBG_DATA_L, data); /* write to RX packet buffer*/ rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_l); } else if (i == 3 || i == 5) { data = context->mask[i - 2]; rtw_write32(adapter, REG_PKTBUF_DBG_DATA_H, data); /* write to RX packet buffer*/ rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_h); } count = 0; do { tmp = rtw_read8(adapter, REG_RXPKTBUF_CTRL); rtw_udelay_os(2); count++; } while (tmp && count < 100); if (count >= 100) res = _FALSE; else res = _TRUE; } /* Disable RX packet buffer access */ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); return res; } void rtw_clean_pattern(_adapter *adapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct rtl_wow_pattern zero_pattern; int i = 0; _rtw_memset(&zero_pattern, 0, sizeof(struct rtl_wow_pattern)); zero_pattern.type = PATTERN_INVALID; for (i = 0; i < MAX_WKFM_CAM_NUM; i++) rtw_write_to_frame_mask(adapter, i, &zero_pattern); rtw_write8(adapter, REG_WKFMCAM_NUM, 0); } static int rtw_hal_set_pattern(_adapter *adapter, u8 *pattern, u8 len, u8 *mask, u8 idx) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct mlme_ext_priv *pmlmeext = NULL; struct mlme_ext_info *pmlmeinfo = NULL; struct rtl_wow_pattern wow_pattern; u8 mask_hw[MAX_WKFM_SIZE] = {0}; u8 content[MAX_WKFM_PATTERN_SIZE] = {0}; u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u8 multicast_addr1[2] = {0x33, 0x33}; u8 multicast_addr2[3] = {0x01, 0x00, 0x5e}; u8 res = _FALSE, index = 0, mask_len = 0; u8 mac_addr[ETH_ALEN] = {0}; u16 count = 0; int i, j; if (pwrctl->wowlan_pattern_idx > MAX_WKFM_CAM_NUM) { RTW_INFO("%s pattern_idx is more than MAX_FMC_NUM: %d\n", __func__, MAX_WKFM_CAM_NUM); return _FALSE; } pmlmeext = &adapter->mlmeextpriv; pmlmeinfo = &pmlmeext->mlmext_info; _rtw_memcpy(mac_addr, adapter_mac_addr(adapter), ETH_ALEN); _rtw_memset(&wow_pattern, 0, sizeof(struct rtl_wow_pattern)); mask_len = DIV_ROUND_UP(len, 8); /* 1. setup A1 table */ if (memcmp(pattern, broadcast_addr, ETH_ALEN) == 0) wow_pattern.type = PATTERN_BROADCAST; else if (memcmp(pattern, multicast_addr1, 2) == 0) wow_pattern.type = PATTERN_MULTICAST; else if (memcmp(pattern, multicast_addr2, 3) == 0) wow_pattern.type = PATTERN_MULTICAST; else if (memcmp(pattern, mac_addr, ETH_ALEN) == 0) wow_pattern.type = PATTERN_UNICAST; else wow_pattern.type = PATTERN_INVALID; /* translate mask from os to mask for hw */ /****************************************************************************** * pattern from OS uses 'ethenet frame', like this: | 6 | 6 | 2 | 20 | Variable | 4 | |--------+--------+------+-----------+------------+-----| | 802.3 Mac Header | IP Header | TCP Packet | FCS | | DA | SA | Type | * BUT, packet catched by our HW is in '802.11 frame', begin from LLC, | 24 or 30 | 6 | 2 | 20 | Variable | 4 | |-------------------+--------+------+-----------+------------+-----| | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | | Others | Tpye | * Therefore, we need translate mask_from_OS to mask_to_hw. * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, * because new mask[0~5] means 'SA', but our HW packet begins from LLC, * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. ******************************************************************************/ /* Shift 6 bits */ for (i = 0; i < mask_len - 1; i++) { mask_hw[i] = mask[i] >> 6; mask_hw[i] |= (mask[i + 1] & 0x3F) << 2; } mask_hw[i] = (mask[i] >> 6) & 0x3F; /* Set bit 0-5 to zero */ mask_hw[0] &= 0xC0; for (i = 0; i < (MAX_WKFM_SIZE / 4); i++) { wow_pattern.mask[i] = mask_hw[i * 4]; wow_pattern.mask[i] |= (mask_hw[i * 4 + 1] << 8); wow_pattern.mask[i] |= (mask_hw[i * 4 + 2] << 16); wow_pattern.mask[i] |= (mask_hw[i * 4 + 3] << 24); } /* To get the wake up pattern from the mask. * We do not count first 12 bits which means * DA[6] and SA[6] in the pattern to match HW design. */ count = 0; for (i = 12; i < len; i++) { if ((mask[i / 8] >> (i % 8)) & 0x01) { content[count] = pattern[i]; count++; } } wow_pattern.crc = rtw_calc_crc(content, count); if (wow_pattern.crc != 0) { if (wow_pattern.type == PATTERN_INVALID) wow_pattern.type = PATTERN_VALID; } index = idx; if (!pwrctl->bInSuspend) index += 2; /* write pattern */ res = rtw_write_to_frame_mask(adapter, index, &wow_pattern); if (res == _FALSE) RTW_INFO("%s: ERROR!! idx: %d write_to_frame_mask_cam fail\n", __func__, idx); return res; } void rtw_fill_pattern(_adapter *adapter) { int i = 0, total = 0, index; struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); struct rtl_wow_pattern wow_pattern; total = pwrpriv->wowlan_pattern_idx; if (total > MAX_WKFM_CAM_NUM) total = MAX_WKFM_CAM_NUM; for (i = 0 ; i < total ; i++) { if (_SUCCESS == rtw_hal_wow_pattern_generate(adapter, i, &wow_pattern)) { index = i; if (!pwrpriv->bInSuspend) index += 2; if (rtw_write_to_frame_mask(adapter, index, &wow_pattern) == _FALSE) RTW_INFO("%s: ERROR!! idx: %d write_to_frame_mask_cam fail\n", __func__, i); } } rtw_write8(adapter, REG_WKFMCAM_NUM, total); } #else /*CONFIG_WOW_PATTERN_HW_CAM*/ #define WOW_CAM_ACCESS_TIMEOUT_MS 200 #define WOW_VALID_BIT BIT31 #define WOW_BC_BIT BIT26 #define WOW_MC_BIT BIT25 #define WOW_UC_BIT BIT24 static u32 _rtw_wow_pattern_read_cam(_adapter *adapter, u8 addr) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); _mutex *mutex = &pwrpriv->wowlan_pattern_cam_mutex; u32 rdata = 0; u32 cnt = 0; systime start = 0; u8 timeout = 0; u8 rst = _FALSE; _enter_critical_mutex(mutex, NULL); rtw_write32(adapter, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 | BIT_WKFCAM_ADDR_V2(addr)); start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(adapter)) break; cnt++; if (0 == (rtw_read32(adapter, REG_WKFMCAM_CMD) & BIT_WKFCAM_POLLING_V1)) { rst = _SUCCESS; break; } if (rtw_get_passing_time_ms(start) > WOW_CAM_ACCESS_TIMEOUT_MS) { timeout = 1; break; } } rdata = rtw_read32(adapter, REG_WKFMCAM_RWD); _exit_critical_mutex(mutex, NULL); /*RTW_INFO("%s ==> addr:0x%02x , rdata:0x%08x\n", __func__, addr, rdata);*/ if (timeout) RTW_ERR(FUNC_ADPT_FMT" failed due to polling timeout\n", FUNC_ADPT_ARG(adapter)); return rdata; } void rtw_wow_pattern_read_cam_ent(_adapter *adapter, u8 id, struct rtl_wow_pattern *context) { int i; u32 rdata; _rtw_memset(context, 0, sizeof(struct rtl_wow_pattern)); for (i = 4; i >= 0; i--) { rdata = _rtw_wow_pattern_read_cam(adapter, (id << 3) | i); switch (i) { case 4: if (rdata & WOW_BC_BIT) context->type = PATTERN_BROADCAST; else if (rdata & WOW_MC_BIT) context->type = PATTERN_MULTICAST; else if (rdata & WOW_UC_BIT) context->type = PATTERN_UNICAST; else context->type = PATTERN_INVALID; context->crc = rdata & 0xFFFF; break; default: _rtw_memcpy(&context->mask[i], (u8 *)(&rdata), 4); break; } } } static void _rtw_wow_pattern_write_cam(_adapter *adapter, u8 addr, u32 wdata) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); _mutex *mutex = &pwrpriv->wowlan_pattern_cam_mutex; u32 cnt = 0; systime start = 0, end = 0; u8 timeout = 0; /*RTW_INFO("%s ==> addr:0x%02x , wdata:0x%08x\n", __func__, addr, wdata);*/ _enter_critical_mutex(mutex, NULL); rtw_write32(adapter, REG_WKFMCAM_RWD, wdata); rtw_write32(adapter, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 | BIT_WKFCAM_WE | BIT_WKFCAM_ADDR_V2(addr)); start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(adapter)) break; cnt++; if (0 == (rtw_read32(adapter, REG_WKFMCAM_CMD) & BIT_WKFCAM_POLLING_V1)) break; if (rtw_get_passing_time_ms(start) > WOW_CAM_ACCESS_TIMEOUT_MS) { timeout = 1; break; } } end = rtw_get_current_time(); _exit_critical_mutex(mutex, NULL); if (timeout) { RTW_ERR(FUNC_ADPT_FMT" addr:0x%02x, wdata:0x%08x, to:%u, polling:%u, %d ms\n" , FUNC_ADPT_ARG(adapter), addr, wdata, timeout, cnt, rtw_get_time_interval_ms(start, end)); } } void rtw_wow_pattern_write_cam_ent(_adapter *adapter, u8 id, struct rtl_wow_pattern *context) { int j; u8 addr; u32 wdata = 0; for (j = 4; j >= 0; j--) { switch (j) { case 4: wdata = context->crc; if (PATTERN_BROADCAST == context->type) wdata |= WOW_BC_BIT; if (PATTERN_MULTICAST == context->type) wdata |= WOW_MC_BIT; if (PATTERN_UNICAST == context->type) wdata |= WOW_UC_BIT; if (PATTERN_INVALID != context->type) wdata |= WOW_VALID_BIT; break; default: wdata = context->mask[j]; break; } addr = (id << 3) + j; _rtw_wow_pattern_write_cam(adapter, addr, wdata); } } static u8 _rtw_wow_pattern_clean_cam(_adapter *adapter) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); _mutex *mutex = &pwrpriv->wowlan_pattern_cam_mutex; u32 cnt = 0; systime start = 0; u8 timeout = 0; u8 rst = _FAIL; _enter_critical_mutex(mutex, NULL); rtw_write32(adapter, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 | BIT_WKFCAM_CLR_V1); start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(adapter)) break; cnt++; if (0 == (rtw_read32(adapter, REG_WKFMCAM_CMD) & BIT_WKFCAM_POLLING_V1)) { rst = _SUCCESS; break; } if (rtw_get_passing_time_ms(start) > WOW_CAM_ACCESS_TIMEOUT_MS) { timeout = 1; break; } } _exit_critical_mutex(mutex, NULL); if (timeout) RTW_ERR(FUNC_ADPT_FMT" falied ,polling timeout\n", FUNC_ADPT_ARG(adapter)); return rst; } void rtw_clean_pattern(_adapter *adapter) { if (_FAIL == _rtw_wow_pattern_clean_cam(adapter)) RTW_ERR("rtw_clean_pattern failed\n"); } void rtw_dump_wow_pattern(void *sel, struct rtl_wow_pattern *pwow_pattern, u8 idx) { int j; RTW_PRINT_SEL(sel, "=======WOW CAM-ID[%d]=======\n", idx); RTW_PRINT_SEL(sel, "[WOW CAM] type:%d\n", pwow_pattern->type); RTW_PRINT_SEL(sel, "[WOW CAM] crc:0x%04x\n", pwow_pattern->crc); for (j = 0; j < 4; j++) RTW_PRINT_SEL(sel, "[WOW CAM] Mask:0x%08x\n", pwow_pattern->mask[j]); } void rtw_fill_pattern(_adapter *adapter) { int i = 0, total = 0; struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); struct rtl_wow_pattern wow_pattern; total = pwrpriv->wowlan_pattern_idx; if (total > MAX_WKFM_CAM_NUM) total = MAX_WKFM_CAM_NUM; for (i = 0 ; i < total ; i++) { if (_SUCCESS == rtw_hal_wow_pattern_generate(adapter, i, &wow_pattern)) { rtw_dump_wow_pattern(RTW_DBGDUMP, &wow_pattern, i); rtw_wow_pattern_write_cam_ent(adapter, i, &wow_pattern); } } } #endif void rtw_wow_pattern_cam_dump(_adapter *adapter) { #ifndef CONFIG_WOW_PATTERN_HW_CAM int i; for (i = 0 ; i < MAX_WKFM_CAM_NUM; i++) { RTW_INFO("=======[%d]=======\n", i); rtw_read_from_frame_mask(adapter, i); } #else struct rtl_wow_pattern context; int i; for (i = 0 ; i < MAX_WKFM_CAM_NUM; i++) { rtw_wow_pattern_read_cam_ent(adapter, i, &context); rtw_dump_wow_pattern(RTW_DBGDUMP, &context, i); } #endif } static void rtw_hal_dl_pattern(_adapter *adapter, u8 mode) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); switch (mode) { case 0: rtw_clean_pattern(adapter); RTW_INFO("%s: total patterns: %d\n", __func__, pwrpriv->wowlan_pattern_idx); break; case 1: rtw_set_default_pattern(adapter); rtw_fill_pattern(adapter); RTW_INFO("%s: pattern total: %d downloaded\n", __func__, pwrpriv->wowlan_pattern_idx); break; case 2: rtw_clean_pattern(adapter); rtw_wow_pattern_sw_reset(adapter); RTW_INFO("%s: clean patterns\n", __func__); break; default: RTW_INFO("%s: unknown mode\n", __func__); break; } } static void rtw_hal_wow_enable(_adapter *adapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct security_priv *psecuritypriv = &adapter->securitypriv; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct hal_ops *pHalFunc = &adapter->hal_func; struct sta_info *psta = NULL; PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter); int res; u16 media_status_rpt; RTW_PRINT("%s, WOWLAN_ENABLE\n", __func__); rtw_hal_gate_bb(adapter, _TRUE); #ifdef CONFIG_GTK_OL if (psecuritypriv->binstallKCK_KEK == _TRUE) rtw_hal_fw_sync_cam_id(adapter); #endif if (IS_HARDWARE_TYPE_8723B(adapter)) rtw_hal_backup_rate(adapter); rtw_hal_fw_dl(adapter, _TRUE); media_status_rpt = RT_MEDIA_CONNECT; rtw_hal_set_hwreg(adapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)&media_status_rpt); /* RX DMA stop */ #if defined(CONFIG_RTL8188E) if (IS_HARDWARE_TYPE_8188E(adapter)) rtw_hal_disable_tx_report(adapter); #endif res = rtw_hal_pause_rx_dma(adapter); if (res == _FAIL) RTW_PRINT("[WARNING] pause RX DMA fail\n"); #ifndef CONFIG_WOW_PATTERN_HW_CAM /* Reconfig RX_FF Boundary */ rtw_hal_set_wow_rxff_boundary(adapter, _TRUE); #endif /* redownload wow pattern */ rtw_hal_dl_pattern(adapter, 1); if (!pwrctl->wowlan_pno_enable) { psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); if (psta != NULL) { #ifdef CONFIG_FW_MULTI_PORT_SUPPORT rtw_hal_set_default_port_id_cmd(adapter, psta->cmn.mac_id); #endif rtw_sta_media_status_rpt(adapter, psta, 1); } } #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) /* Enable CPWM2 only. */ res = rtw_hal_enable_cpwm2(adapter); if (res == _FAIL) RTW_PRINT("[WARNING] enable cpwm2 fail\n"); #endif #ifdef CONFIG_GPIO_WAKEUP rtw_hal_switch_gpio_wl_ctrl(adapter, WAKEUP_GPIO_IDX, _TRUE); #endif /* Set WOWLAN H2C command. */ RTW_PRINT("Set WOWLan cmd\n"); rtw_hal_set_fw_wow_related_cmd(adapter, 1); res = rtw_hal_check_wow_ctrl(adapter, _TRUE); if (res == _FALSE) RTW_INFO("[Error]%s: set wowlan CMD fail!!\n", __func__); pwrctl->wowlan_wake_reason = rtw_read8(adapter, REG_WOWLAN_WAKE_REASON); RTW_PRINT("wowlan_wake_reason: 0x%02x\n", pwrctl->wowlan_wake_reason); #ifdef CONFIG_GTK_OL_DBG dump_sec_cam(RTW_DBGDUMP, adapter); dump_sec_cam_cache(RTW_DBGDUMP, adapter); #endif #ifdef CONFIG_USB_HCI /* free adapter's resource */ rtw_mi_intf_stop(adapter); #endif #if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) /* Invoid SE0 reset signal during suspending*/ rtw_write8(adapter, REG_RSV_CTRL, 0x20); if (IS_8188F(pHalData->version_id) == FALSE) rtw_write8(adapter, REG_RSV_CTRL, 0x60); #endif rtw_hal_gate_bb(adapter, _FALSE); } #define DBG_WAKEUP_REASON #ifdef DBG_WAKEUP_REASON void _dbg_wake_up_reason_string(_adapter *adapter, const char *srt_res) { RTW_INFO(ADPT_FMT "- wake up reason - %s\n", ADPT_ARG(adapter), srt_res); } void _dbg_rtw_wake_up_reason(_adapter *adapter, u8 reason) { if (RX_PAIRWISEKEY == reason) _dbg_wake_up_reason_string(adapter, "Rx pairwise key"); else if (RX_GTK == reason) _dbg_wake_up_reason_string(adapter, "Rx GTK"); else if (RX_FOURWAY_HANDSHAKE == reason) _dbg_wake_up_reason_string(adapter, "Rx four way handshake"); else if (RX_DISASSOC == reason) _dbg_wake_up_reason_string(adapter, "Rx disassoc"); else if (RX_DEAUTH == reason) _dbg_wake_up_reason_string(adapter, "Rx deauth"); else if (RX_ARP_REQUEST == reason) _dbg_wake_up_reason_string(adapter, "Rx ARP request"); else if (FW_DECISION_DISCONNECT == reason) _dbg_wake_up_reason_string(adapter, "FW detect disconnect"); else if (RX_MAGIC_PKT == reason) _dbg_wake_up_reason_string(adapter, "Rx magic packet"); else if (RX_UNICAST_PKT == reason) _dbg_wake_up_reason_string(adapter, "Rx unicast packet"); else if (RX_PATTERN_PKT == reason) _dbg_wake_up_reason_string(adapter, "Rx pattern packet"); else if (RTD3_SSID_MATCH == reason) _dbg_wake_up_reason_string(adapter, "RTD3 SSID match"); else if (RX_REALWOW_V2_WAKEUP_PKT == reason) _dbg_wake_up_reason_string(adapter, "Rx real WOW V2 wakeup packet"); else if (RX_REALWOW_V2_ACK_LOST == reason) _dbg_wake_up_reason_string(adapter, "Rx real WOW V2 ack lost"); else if (ENABLE_FAIL_DMA_IDLE == reason) _dbg_wake_up_reason_string(adapter, "enable fail DMA idle"); else if (ENABLE_FAIL_DMA_PAUSE == reason) _dbg_wake_up_reason_string(adapter, "enable fail DMA pause"); else if (AP_OFFLOAD_WAKEUP == reason) _dbg_wake_up_reason_string(adapter, "AP offload wakeup"); else if (CLK_32K_UNLOCK == reason) _dbg_wake_up_reason_string(adapter, "clk 32k unlock"); else if (RTIME_FAIL_DMA_IDLE == reason) _dbg_wake_up_reason_string(adapter, "RTIME fail DMA idle"); else if (CLK_32K_LOCK == reason) _dbg_wake_up_reason_string(adapter, "clk 32k lock"); else _dbg_wake_up_reason_string(adapter, "unknown reasoen"); } #endif static void rtw_hal_wow_disable(_adapter *adapter) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); struct security_priv *psecuritypriv = &adapter->securitypriv; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct hal_ops *pHalFunc = &adapter->hal_func; struct sta_info *psta = NULL; int res; u16 media_status_rpt; u8 val8; RTW_PRINT("%s, WOWLAN_DISABLE\n", __func__); if (!pwrctl->wowlan_pno_enable) { psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); if (psta != NULL) rtw_sta_media_status_rpt(adapter, psta, 0); else RTW_INFO("%s: psta is null\n", __func__); } if (0) { RTW_INFO("0x630:0x%02x\n", rtw_read8(adapter, 0x630)); RTW_INFO("0x631:0x%02x\n", rtw_read8(adapter, 0x631)); RTW_INFO("0x634:0x%02x\n", rtw_read8(adapter, 0x634)); RTW_INFO("0x1c7:0x%02x\n", rtw_read8(adapter, 0x1c7)); } pwrctl->wowlan_wake_reason = rtw_read8(adapter, REG_WOWLAN_WAKE_REASON); RTW_PRINT("wakeup_reason: 0x%02x\n", pwrctl->wowlan_wake_reason); #ifdef DBG_WAKEUP_REASON _dbg_rtw_wake_up_reason(adapter, pwrctl->wowlan_wake_reason); #endif rtw_hal_set_fw_wow_related_cmd(adapter, 0); res = rtw_hal_check_wow_ctrl(adapter, _FALSE); if (res == _FALSE) { RTW_INFO("[Error]%s: disable WOW cmd fail\n!!", __func__); rtw_hal_force_enable_rxdma(adapter); } rtw_hal_gate_bb(adapter, _TRUE); res = rtw_hal_pause_rx_dma(adapter); if (res == _FAIL) RTW_PRINT("[WARNING] pause RX DMA fail\n"); /* clean HW pattern match */ rtw_hal_dl_pattern(adapter, 0); #ifndef CONFIG_WOW_PATTERN_HW_CAM /* config RXFF boundary to original */ rtw_hal_set_wow_rxff_boundary(adapter, _FALSE); #endif rtw_hal_release_rx_dma(adapter); #if defined(CONFIG_RTL8188E) if (IS_HARDWARE_TYPE_8188E(adapter)) rtw_hal_enable_tx_report(adapter); #endif if ((pwrctl->wowlan_wake_reason != RX_DISASSOC) || (pwrctl->wowlan_wake_reason != RX_DEAUTH) || (pwrctl->wowlan_wake_reason != FW_DECISION_DISCONNECT)) { rtw_hal_get_aoac_rpt(adapter); rtw_hal_update_sw_security_info(adapter); } rtw_hal_fw_dl(adapter, _FALSE); #ifdef CONFIG_GPIO_WAKEUP #ifdef CONFIG_WAKEUP_GPIO_INPUT_MODE if (pwrctl->is_high_active == 0) rtw_hal_set_input_gpio(adapter, WAKEUP_GPIO_IDX); else rtw_hal_set_output_gpio(adapter, WAKEUP_GPIO_IDX, 0); #else val8 = (pwrctl->is_high_active == 0) ? 1 : 0; RTW_PRINT("Set Wake GPIO to default(%d).\n", val8); rtw_hal_set_output_gpio(adapter, WAKEUP_GPIO_IDX, val8); rtw_hal_switch_gpio_wl_ctrl(adapter, WAKEUP_GPIO_IDX, _FALSE); #endif #endif if ((pwrctl->wowlan_wake_reason != FW_DECISION_DISCONNECT) && (pwrctl->wowlan_wake_reason != RX_PAIRWISEKEY) && (pwrctl->wowlan_wake_reason != RX_DISASSOC) && (pwrctl->wowlan_wake_reason != RX_DEAUTH)) { media_status_rpt = RT_MEDIA_CONNECT; rtw_hal_set_hwreg(adapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)&media_status_rpt); if (psta != NULL) { #ifdef CONFIG_FW_MULTI_PORT_SUPPORT rtw_hal_set_default_port_id_cmd(adapter, psta->cmn.mac_id); #endif rtw_sta_media_status_rpt(adapter, psta, 1); } } rtw_hal_gate_bb(adapter, _FALSE); } #endif /*CONFIG_WOWLAN*/ #ifdef CONFIG_P2P_WOWLAN void rtw_hal_set_p2p_wow_fw_rsvd_page(_adapter *adapter, u8 *pframe, u16 index, u8 tx_desc, u32 page_size, u8 *page_num, u32 *total_pkt_len, RSVDPAGE_LOC *rsvd_page_loc) { u32 P2PNegoRspLength = 0, P2PInviteRspLength = 0; u32 P2PPDRspLength = 0, P2PProbeRspLength = 0, P2PBCNLength = 0; u8 CurtPktPageNum = 0; /* P2P Beacon */ rsvd_page_loc->LocP2PBeacon = *page_num; rtw_hal_construct_P2PBeacon(adapter, &pframe[index], &P2PBCNLength); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], P2PBCNLength, _FALSE, _FALSE, _FALSE); #if 0 RTW_INFO("%s(): HW_VAR_SET_TX_CMD: PROBE RSP %p %d\n", __FUNCTION__, &pframe[index - tx_desc], (P2PBCNLength + tx_desc)); #endif CurtPktPageNum = (u8)PageNum(tx_desc + P2PBCNLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-P2P-Beacon", CurtPktPageNum, *page_num, 0); #endif /* P2P Probe rsp */ rsvd_page_loc->LocP2PProbeRsp = *page_num; rtw_hal_construct_P2PProbeRsp(adapter, &pframe[index], &P2PProbeRspLength); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], P2PProbeRspLength, _FALSE, _FALSE, _FALSE); /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: PROBE RSP %p %d\n", */ /* __FUNCTION__, &pframe[index-tx_desc], (P2PProbeRspLength+tx_desc)); */ CurtPktPageNum = (u8)PageNum(tx_desc + P2PProbeRspLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-P2P-ProbeRsp", CurtPktPageNum, *page_num, 0); #endif /* P2P nego rsp */ rsvd_page_loc->LocNegoRsp = *page_num; rtw_hal_construct_P2PNegoRsp(adapter, &pframe[index], &P2PNegoRspLength); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], P2PNegoRspLength, _FALSE, _FALSE, _FALSE); /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ /* __FUNCTION__, &pframe[index-tx_desc], (NegoRspLength+tx_desc)); */ CurtPktPageNum = (u8)PageNum(tx_desc + P2PNegoRspLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-P2P-NegoRsp", CurtPktPageNum, *page_num, 0); #endif /* P2P invite rsp */ rsvd_page_loc->LocInviteRsp = *page_num; rtw_hal_construct_P2PInviteRsp(adapter, &pframe[index], &P2PInviteRspLength); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], P2PInviteRspLength, _FALSE, _FALSE, _FALSE); /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ /* __FUNCTION__, &pframe[index-tx_desc], (InviteRspLength+tx_desc)); */ CurtPktPageNum = (u8)PageNum(tx_desc + P2PInviteRspLength, page_size); *page_num += CurtPktPageNum; index += (CurtPktPageNum * page_size); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-P2P-InviteRsp", CurtPktPageNum, *page_num, 0); #endif /* P2P provision discovery rsp */ rsvd_page_loc->LocPDRsp = *page_num; rtw_hal_construct_P2PProvisionDisRsp(adapter, &pframe[index], &P2PPDRspLength); rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], P2PPDRspLength, _FALSE, _FALSE, _FALSE); /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ /* __FUNCTION__, &pframe[index-tx_desc], (PDRspLength+tx_desc)); */ CurtPktPageNum = (u8)PageNum(tx_desc + P2PPDRspLength, page_size); *page_num += CurtPktPageNum; *total_pkt_len = index + P2PPDRspLength; #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("WOW-P2P-PDR", CurtPktPageNum, *page_num, *total_pkt_len); #endif index += (CurtPktPageNum * page_size); } #endif /* CONFIG_P2P_WOWLAN */ #ifdef CONFIG_LPS_PG #include "hal_halmac.h" #define DBG_LPSPG_SEC_DUMP #define LPS_PG_INFO_RSVD_LEN 16 #define LPS_PG_INFO_RSVD_PAGE_NUM 1 #define DBG_LPSPG_INFO_DUMP static void rtw_hal_set_lps_pg_info_rsvd_page(_adapter *adapter) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); struct sta_info *psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(&adapter->mlmepriv)); struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); PHAL_DATA_TYPE phal_data = GET_HAL_DATA(adapter); u8 lps_pg_info[LPS_PG_INFO_RSVD_LEN] = {0}; #ifdef CONFIG_MBSSID_CAM u8 cam_id = INVALID_CAM_ID; #endif u8 *psec_cam_id = lps_pg_info + 8; u8 sec_cam_num = 0; u8 drv_rsvdpage_num = 0; if (!psta) { RTW_ERR("%s [ERROR] sta is NULL\n", __func__); rtw_warn_on(1); return; } /*Byte 0 - used macid*/ LPSPG_RSVD_PAGE_SET_MACID(lps_pg_info, psta->cmn.mac_id); RTW_INFO("[LPSPG-INFO] mac_id:%d\n", psta->cmn.mac_id); #ifdef CONFIG_MBSSID_CAM /*Byte 1 - used BSSID CAM entry*/ cam_id = rtw_mbid_cam_search_by_ifaceid(adapter, adapter->iface_id); if (cam_id != INVALID_CAM_ID) LPSPG_RSVD_PAGE_SET_MBSSCAMID(lps_pg_info, cam_id); RTW_INFO("[LPSPG-INFO] mbss_cam_id:%d\n", cam_id); #endif #ifdef CONFIG_WOWLAN /*&& pattern match cam used*/ /*Btye 2 - Max used Pattern Match CAM entry*/ if (pwrpriv->wowlan_mode == _TRUE && check_fwstate(&adapter->mlmepriv, _FW_LINKED) == _TRUE) { LPSPG_RSVD_PAGE_SET_PMC_NUM(lps_pg_info, pwrpriv->wowlan_pattern_idx); RTW_INFO("[LPSPG-INFO] Max Pattern Match CAM entry :%d\n", pwrpriv->wowlan_pattern_idx); } #endif #ifdef CONFIG_BEAMFORMING /*&& MU BF*/ /*Btye 3 - Max MU rate table Group ID*/ LPSPG_RSVD_PAGE_SET_MU_RAID_GID(lps_pg_info, 0); RTW_INFO("[LPSPG-INFO] Max MU rate table Group ID :%d\n", 0); #endif /*Btye 8 ~15 - used Security CAM entry */ sec_cam_num = rtw_get_sec_camid(adapter, 8, psec_cam_id); /*Btye 4 - used Security CAM entry number*/ if (sec_cam_num < 8) LPSPG_RSVD_PAGE_SET_SEC_CAM_NUM(lps_pg_info, sec_cam_num); RTW_INFO("[LPSPG-INFO] Security CAM entry number :%d\n", sec_cam_num); /*Btye 5 - Txbuf used page number for fw offload*/ if (pwrpriv->wowlan_mode == _TRUE || pwrpriv->wowlan_ap_mode == _TRUE) drv_rsvdpage_num = rtw_hal_get_txbuff_rsvd_page_num(adapter, _TRUE); else drv_rsvdpage_num = rtw_hal_get_txbuff_rsvd_page_num(adapter, _FALSE); LPSPG_RSVD_PAGE_SET_DRV_RSVDPAGE_NUM(lps_pg_info, drv_rsvdpage_num); RTW_INFO("[LPSPG-INFO] DRV's rsvd page numbers :%d\n", drv_rsvdpage_num); #ifdef DBG_LPSPG_SEC_DUMP { int i; for (i = 0; i < sec_cam_num; i++) RTW_INFO("%d = sec_cam_id:%d\n", i, psec_cam_id[i]); } #endif #ifdef DBG_LPSPG_INFO_DUMP RTW_INFO("==== DBG_LPSPG_INFO_RSVD_PAGE_DUMP====\n"); RTW_INFO(" %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", *(lps_pg_info), *(lps_pg_info + 1), *(lps_pg_info + 2), *(lps_pg_info + 3), *(lps_pg_info + 4), *(lps_pg_info + 5), *(lps_pg_info + 6), *(lps_pg_info + 7)); RTW_INFO(" %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", *(lps_pg_info + 8), *(lps_pg_info + 9), *(lps_pg_info + 10), *(lps_pg_info + 11), *(lps_pg_info + 12), *(lps_pg_info + 13), *(lps_pg_info + 14), *(lps_pg_info + 15)); RTW_INFO("==== DBG_LPSPG_INFO_RSVD_PAGE_DUMP====\n"); #endif rtw_halmac_download_rsvd_page(dvobj, pwrpriv->lpspg_rsvd_page_locate, lps_pg_info, LPS_PG_INFO_RSVD_LEN); #ifdef DBG_LPSPG_INFO_DUMP RTW_INFO("Get LPS-PG INFO from rsvd page_offset:%d\n", pwrpriv->lpspg_rsvd_page_locate); rtw_dump_rsvd_page(RTW_DBGDUMP, adapter, pwrpriv->lpspg_rsvd_page_locate, 1); #endif } static u8 rtw_hal_set_lps_pg_info_cmd(_adapter *adapter) { struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); struct mlme_priv *pmlmepriv = &adapter->mlmepriv; u8 lpspg_info[H2C_LPS_PG_INFO_LEN] = {0}; u8 ret = _FAIL; RTW_INFO("%s: loc_lpspg_info:%d\n", __func__, pwrpriv->lpspg_rsvd_page_locate); if (_NO_PRIVACY_ != adapter->securitypriv.dot11PrivacyAlgrthm) SET_H2CCMD_LPSPG_SEC_CAM_EN(lpspg_info, 1); /*SecurityCAM_En*/ #ifdef CONFIG_MBSSID_CAM SET_H2CCMD_LPSPG_MBID_CAM_EN(lpspg_info, 1); /*BSSIDCAM_En*/ #endif #if defined(CONFIG_WOWLAN) && defined(CONFIG_WOW_PATTERN_HW_CAM) if (pwrpriv->wowlan_mode == _TRUE && check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { SET_H2CCMD_LPSPG_PMC_CAM_EN(lpspg_info, 1); /*PatternMatchCAM_En*/ } #endif #ifdef CONFIG_MACID_SEARCH SET_H2CCMD_LPSPG_MACID_SEARCH_EN(lpspg_info, 1); /*MACIDSearch_En*/ #endif #ifdef CONFIG_TX_SC SET_H2CCMD_LPSPG_TXSC_EN(lpspg_info, 1); /*TXSC_En*/ #endif #ifdef CONFIG_BEAMFORMING /*&& MU BF*/ SET_H2CCMD_LPSPG_MU_RATE_TB_EN(lpspg_info, 1); /*MURateTable_En*/ #endif SET_H2CCMD_LPSPG_LOC(lpspg_info, pwrpriv->lpspg_rsvd_page_locate); #ifdef DBG_LPSPG_INFO_DUMP RTW_INFO("==== DBG_LPSPG_INFO_CMD_DUMP====\n"); RTW_INFO(" H2C_CMD: 0x%02x, H2C_LEN: %d\n", H2C_LPS_PG_INFO, H2C_LPS_PG_INFO_LEN); RTW_INFO(" %02X:%02X\n", *(lpspg_info), *(lpspg_info + 1)); RTW_INFO("==== DBG_LPSPG_INFO_CMD_DUMP====\n"); #endif ret = rtw_hal_fill_h2c_cmd(adapter, H2C_LPS_PG_INFO, H2C_LPS_PG_INFO_LEN, lpspg_info); return ret; } u8 rtw_hal_set_lps_pg_info(_adapter *adapter) { u8 ret = _FAIL; struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); if (pwrpriv->lpspg_rsvd_page_locate == 0) { RTW_ERR("%s [ERROR] lpspg_rsvd_page_locate = 0\n", __func__); rtw_warn_on(1); return ret; } rtw_hal_set_lps_pg_info_rsvd_page(adapter); ret = rtw_hal_set_lps_pg_info_cmd(adapter); if (_SUCCESS == ret) pwrpriv->blpspg_info_up = _FALSE; return ret; } void rtw_hal_lps_pg_rssi_lv_decide(_adapter *adapter, struct sta_info *sta) { #if 0 if (sta->cmn.ra_info.rssi_level >= 4) sta->lps_pg_rssi_lv = 3; /*RSSI High - 1SS_VHT_MCS7*/ else if (sta->cmn.ra_info.rssi_level >= 2) sta->lps_pg_rssi_lv = 2; /*RSSI Middle - 1SS_VHT_MCS3*/ else sta->lps_pg_rssi_lv = 1; /*RSSI Lower - Lowest_rate*/ #else sta->lps_pg_rssi_lv = 0; #endif RTW_INFO("%s mac-id:%d, rssi:%d, rssi_level:%d, lps_pg_rssi_lv:%d\n", __func__, sta->cmn.mac_id, sta->cmn.rssi_stat.rssi, sta->cmn.ra_info.rssi_level, sta->lps_pg_rssi_lv); } void rtw_hal_lps_pg_handler(_adapter *adapter, enum lps_pg_hdl_id hdl_id) { switch (hdl_id) { case LPS_PG_INFO_CFG: rtw_hal_set_lps_pg_info(adapter); break; case LPS_PG_REDLEMEM: { /*set xmit_block*/ rtw_set_xmit_block(adapter, XMIT_BLOCK_REDLMEM); if (_FAIL == rtw_hal_fw_mem_dl(adapter, FW_EMEM)) rtw_warn_on(1); /*clearn xmit_block*/ rtw_clr_xmit_block(adapter, XMIT_BLOCK_REDLMEM); } break; case LPS_PG_RESEND_H2C: { struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl; struct sta_info *sta; int i; for (i = 0; i < MACID_NUM_SW_LIMIT; i++) { sta = macid_ctl->sta[i]; if (sta && !is_broadcast_mac_addr(sta->cmn.mac_addr)) { rtw_hal_lps_pg_rssi_lv_decide(adapter, sta); set_sta_rate(adapter, sta); sta->lps_pg_rssi_lv = 0; } } } break; default: break; } } #endif /*CONFIG_LPS_PG*/ /* * Description: Fill the reserved packets that FW will use to RSVD page. * Now we just send 4 types packet to rsvd page. * (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. * Input: * finished - FALSE:At the first time we will send all the packets as a large packet to Hw, * so we need to set the packet length to total lengh. * TRUE: At the second time, we should send the first packet (default:beacon) * to Hw again and set the lengh in descriptor to the real beacon lengh. * page_num - The amount of reserved page which driver need. * If this is not NULL, this function doesn't real download reserved * page, but just count the number of reserved page. * * 2009.10.15 by tynli. * 2017.06.20 modified by Lucas. * * Page Size = 128: 8188e, 8723a/b, 8192c/d, * Page Size = 256: 8192e, 8821a * Page Size = 512: 8812a */ /*#define DBG_DUMP_SET_RSVD_PAGE*/ static void _rtw_hal_set_fw_rsvd_page(_adapter *adapter, bool finished, u8 *page_num) { PHAL_DATA_TYPE pHalData; struct xmit_frame *pcmdframe = NULL; struct pkt_attrib *pattrib; struct xmit_priv *pxmitpriv; struct mlme_ext_priv *pmlmeext; struct mlme_ext_info *pmlmeinfo; struct pwrctrl_priv *pwrctl; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct hal_ops *pHalFunc = &adapter->hal_func; u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength = 0; u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0; u32 ProbeReqLength = 0, NullFunctionDataLength = 0; u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; u8 TotalPageNum = 0 , CurtPktPageNum = 0 , RsvdPageNum = 0; u8 *ReservedPagePacket; u16 BufIndex = 0; u32 TotalPacketLen = 0, MaxRsvdPageBufSize = 0, PageSize = 0; RSVDPAGE_LOC RsvdPageLoc; #ifdef DBG_FW_DEBUG_MSG_PKT u32 fw_dbg_msg_pkt_len = 0; #endif /*DBG_FW_DEBUG_MSG_PKT*/ #ifdef DBG_CONFIG_ERROR_DETECT struct sreset_priv *psrtpriv; #endif /* DBG_CONFIG_ERROR_DETECT */ #ifdef CONFIG_MCC_MODE u8 dl_mcc_page = _FAIL; #endif /* CONFIG_MCC_MODE */ pHalData = GET_HAL_DATA(adapter); #ifdef DBG_CONFIG_ERROR_DETECT psrtpriv = &pHalData->srestpriv; #endif pxmitpriv = &adapter->xmitpriv; pmlmeext = &adapter->mlmeextpriv; pmlmeinfo = &pmlmeext->mlmext_info; pwrctl = adapter_to_pwrctl(adapter); rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, (u8 *)&PageSize); if (PageSize == 0) { RTW_INFO("[Error]: %s, PageSize is zero!!\n", __func__); return; } /* Prepare ReservedPagePacket */ if (page_num) { ReservedPagePacket = rtw_zmalloc(MAX_CMDBUF_SZ); if (!ReservedPagePacket) { RTW_WARN("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__); *page_num = 0xFF; return; } } else { if (pwrctl->wowlan_mode == _TRUE || pwrctl->wowlan_ap_mode == _TRUE) RsvdPageNum = rtw_hal_get_txbuff_rsvd_page_num(adapter, _TRUE); else RsvdPageNum = rtw_hal_get_txbuff_rsvd_page_num(adapter, _FALSE); RTW_INFO("%s PageSize: %d, RsvdPageNUm: %d\n", __func__, PageSize, RsvdPageNum); MaxRsvdPageBufSize = RsvdPageNum * PageSize; if (MaxRsvdPageBufSize > MAX_CMDBUF_SZ) { RTW_ERR("%s MaxRsvdPageBufSize(%d) is larger than MAX_CMDBUF_SZ(%d)", __func__, MaxRsvdPageBufSize, MAX_CMDBUF_SZ); rtw_warn_on(1); return; } pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); if (pcmdframe == NULL) { RTW_ERR("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__); return; } ReservedPagePacket = pcmdframe->buf_addr; } _rtw_memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); /* beacon * 1 pages */ BufIndex = TxDescOffset; rtw_hal_construct_beacon(adapter, &ReservedPagePacket[BufIndex], &BeaconLength); /* * When we count the first page size, we need to reserve description size for the RSVD * packet, it will be filled in front of the packet in TXPKTBUF. */ CurtPktPageNum = (u8)PageNum((TxDescLen + BeaconLength), PageSize); TotalPageNum += CurtPktPageNum; BufIndex += (CurtPktPageNum * PageSize); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("Beacon", CurtPktPageNum, TotalPageNum, TotalPacketLen); #endif if (pwrctl->wowlan_ap_mode == _TRUE) { /* (4) probe response*/ RsvdPageLoc.LocProbeRsp = TotalPageNum; rtw_hal_construct_ProbeRsp( adapter, &ReservedPagePacket[BufIndex], &ProbeRspLength, get_my_bssid(&pmlmeinfo->network), _FALSE); rtw_hal_fill_fake_txdesc(adapter, &ReservedPagePacket[BufIndex - TxDescLen], ProbeRspLength, _FALSE, _FALSE, _FALSE); CurtPktPageNum = (u8)PageNum(TxDescLen + ProbeRspLength, PageSize); TotalPageNum += CurtPktPageNum; TotalPacketLen = BufIndex + ProbeRspLength; BufIndex += (CurtPktPageNum * PageSize); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("ProbeRsp", CurtPktPageNum, TotalPageNum, TotalPacketLen); #endif goto download_page; } /* ps-poll * 1 page */ RsvdPageLoc.LocPsPoll = TotalPageNum; RTW_INFO("LocPsPoll: %d\n", RsvdPageLoc.LocPsPoll); rtw_hal_construct_PSPoll(adapter, &ReservedPagePacket[BufIndex], &PSPollLength); rtw_hal_fill_fake_txdesc(adapter, &ReservedPagePacket[BufIndex - TxDescLen], PSPollLength, _TRUE, _FALSE, _FALSE); CurtPktPageNum = (u8)PageNum((TxDescLen + PSPollLength), PageSize); TotalPageNum += CurtPktPageNum; BufIndex += (CurtPktPageNum * PageSize); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("PSPoll", CurtPktPageNum, TotalPageNum, TotalPacketLen); #endif #ifdef CONFIG_BT_COEXIST if (pwrctl->wowlan_mode == _FALSE || pwrctl->wowlan_in_resume == _TRUE) { /* BT Qos null data * 1 page */ RsvdPageLoc.LocBTQosNull = TotalPageNum; RTW_INFO("LocBTQosNull: %d\n", RsvdPageLoc.LocBTQosNull); rtw_hal_construct_NullFunctionData(adapter, &ReservedPagePacket[BufIndex], &BTQosNullLength, get_my_bssid(&pmlmeinfo->network), _TRUE, 0, 0, _FALSE); rtw_hal_fill_fake_txdesc(adapter, &ReservedPagePacket[BufIndex - TxDescLen], BTQosNullLength, _FALSE, _TRUE, _FALSE); CurtPktPageNum = (u8)PageNum(TxDescLen + BTQosNullLength, PageSize); TotalPageNum += CurtPktPageNum; BufIndex += (CurtPktPageNum * PageSize); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("BTQosNull", CurtPktPageNum, TotalPageNum, TotalPacketLen); #endif } #endif /* CONFIG_BT_COEXIT */ #ifdef CONFIG_MCC_MODE if (MCC_EN(adapter)) { dl_mcc_page = rtw_hal_dl_mcc_fw_rsvd_page(adapter, ReservedPagePacket, &BufIndex, TxDescLen, PageSize, &TotalPageNum, &RsvdPageLoc, page_num); } else { dl_mcc_page = _FAIL; } if (dl_mcc_page == _FAIL) #endif /* CONFIG_MCC_MODE */ { /* null data * 1 page */ RsvdPageLoc.LocNullData = TotalPageNum; RTW_INFO("LocNullData: %d\n", RsvdPageLoc.LocNullData); rtw_hal_construct_NullFunctionData( adapter, &ReservedPagePacket[BufIndex], &NullDataLength, get_my_bssid(&pmlmeinfo->network), _FALSE, 0, 0, _FALSE); rtw_hal_fill_fake_txdesc(adapter, &ReservedPagePacket[BufIndex - TxDescLen], NullDataLength, _FALSE, _FALSE, _FALSE); CurtPktPageNum = (u8)PageNum(TxDescLen + NullDataLength, PageSize); TotalPageNum += CurtPktPageNum; BufIndex += (CurtPktPageNum * PageSize); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("NullData", CurtPktPageNum, TotalPageNum, TotalPacketLen); #endif } if (pwrctl->wowlan_mode == _FALSE || pwrctl->wowlan_in_resume == _TRUE) { /* Qos null data * 1 page */ RsvdPageLoc.LocQosNull = TotalPageNum; RTW_INFO("LocQosNull: %d\n", RsvdPageLoc.LocQosNull); rtw_hal_construct_NullFunctionData(adapter, &ReservedPagePacket[BufIndex], &QosNullLength, get_my_bssid(&pmlmeinfo->network), _TRUE, 0, 0, _FALSE); rtw_hal_fill_fake_txdesc(adapter, &ReservedPagePacket[BufIndex - TxDescLen], QosNullLength, _FALSE, _FALSE, _FALSE); CurtPktPageNum = (u8)PageNum(TxDescLen + QosNullLength, PageSize); TotalPageNum += CurtPktPageNum; BufIndex += (CurtPktPageNum * PageSize); #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("QosNull", CurtPktPageNum, TotalPageNum, TotalPacketLen); #endif } TotalPacketLen = BufIndex; #ifdef DBG_FW_DEBUG_MSG_PKT RsvdPageLoc.loc_fw_dbg_msg_pkt = TotalPageNum; RTW_INFO("loc_fw_dbg_msg_pkt: %d\n", RsvdPageLoc.loc_fw_dbg_msg_pkt); rtw_hal_construct_fw_dbg_msg_pkt( adapter, &ReservedPagePacket[BufIndex], &fw_dbg_msg_pkt_len); rtw_hal_fill_fake_txdesc(adapter, &ReservedPagePacket[BufIndex - TxDescLen], fw_dbg_msg_pkt_len, _FALSE, _FALSE, _FALSE); CurtPktPageNum = (u8)PageNum(TxDescLen + fw_dbg_msg_pkt_len, PageSize); TotalPageNum += CurtPktPageNum; TotalPacketLen = BufIndex + fw_dbg_msg_pkt_len; BufIndex += (CurtPktPageNum * PageSize); #endif /*DBG_FW_DEBUG_MSG_PKT*/ #ifdef CONFIG_WOWLAN if (pwrctl->wowlan_mode == _TRUE && pwrctl->wowlan_in_resume == _FALSE) { rtw_hal_set_wow_fw_rsvd_page(adapter, ReservedPagePacket, BufIndex, TxDescLen, PageSize, &TotalPageNum, &TotalPacketLen, &RsvdPageLoc); } #endif /* CONFIG_WOWLAN */ #ifdef CONFIG_P2P_WOWLAN if (_TRUE == pwrctl->wowlan_p2p_mode) { rtw_hal_set_p2p_wow_fw_rsvd_page(adapter, ReservedPagePacket, BufIndex, TxDescLen, PageSize, &TotalPageNum, &TotalPacketLen, &RsvdPageLoc); } #endif /* CONFIG_P2P_WOWLAN */ #ifdef CONFIG_LPS_PG /* must reserved last 1 x page for LPS PG Info*/ pwrctl->lpspg_rsvd_page_locate = TotalPageNum; pwrctl->blpspg_info_up = _TRUE; if (page_num) TotalPageNum += LPS_PG_INFO_RSVD_PAGE_NUM; #ifdef DBG_RSVD_PAGE_CFG RSVD_PAGE_CFG("LPS_PG", LPS_PG_INFO_RSVD_PAGE_NUM, (page_num) ? TotalPageNum : (TotalPageNum + LPS_PG_INFO_RSVD_PAGE_NUM), TotalPacketLen); #endif #endif /*Note: BufIndex already add a TxDescOffset offset in first Beacon page * The "TotalPacketLen" is calculate by BufIndex. * We need to decrease TxDescOffset before doing length check. by yiwei */ TotalPacketLen = TotalPacketLen - TxDescOffset; download_page: if (page_num) { *page_num = TotalPageNum; rtw_mfree(ReservedPagePacket, MAX_CMDBUF_SZ); ReservedPagePacket = NULL; return; } /* RTW_INFO("%s BufIndex(%d), TxDescLen(%d), PageSize(%d)\n",__func__, BufIndex, TxDescLen, PageSize);*/ RTW_INFO("%s PageNum(%d), pktlen(%d)\n", __func__, TotalPageNum, TotalPacketLen); #ifdef CONFIG_LPS_PG if ((TotalPageNum + LPS_PG_INFO_RSVD_PAGE_NUM) > RsvdPageNum) { pwrctl->lpspg_rsvd_page_locate = 0; pwrctl->blpspg_info_up = _FALSE; RTW_ERR("%s [LPS_PG] rsvd page %d is not enough! need %d pages\n", __func__, RsvdPageNum, (TotalPageNum + LPS_PG_INFO_RSVD_PAGE_NUM)); rtw_warn_on(1); } #endif if (TotalPacketLen > MaxRsvdPageBufSize) { RTW_ERR("%s : rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", __FUNCTION__, TotalPacketLen, MaxRsvdPageBufSize); rtw_warn_on(1); goto error; } else { /* update attribute */ pattrib = &pcmdframe->attrib; update_mgntframe_attrib(adapter, pattrib); pattrib->qsel = QSLT_BEACON; pattrib->pktlen = TotalPacketLen; pattrib->last_txcmdsz = TotalPacketLen; #ifdef CONFIG_PCI_HCI dump_mgntframe(adapter, pcmdframe); #else dump_mgntframe_and_wait(adapter, pcmdframe, 100); #endif } RTW_INFO("%s: Set RSVD page location to Fw ,TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); #ifdef DBG_DUMP_SET_RSVD_PAGE RTW_INFO(" ==================================================\n"); RTW_INFO_DUMP("\n", ReservedPagePacket, TotalPacketLen); RTW_INFO(" ==================================================\n"); #endif if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { rtw_hal_set_FwRsvdPage_cmd(adapter, &RsvdPageLoc); #ifdef DBG_FW_DEBUG_MSG_PKT rtw_hal_set_fw_dbg_msg_pkt_rsvd_page_cmd(adapter, &RsvdPageLoc); #endif /*DBG_FW_DEBUG_MSG_PKT*/ #ifdef CONFIG_WOWLAN if (pwrctl->wowlan_mode == _TRUE && pwrctl->wowlan_in_resume == _FALSE) rtw_hal_set_FwAoacRsvdPage_cmd(adapter, &RsvdPageLoc); #endif /* CONFIG_WOWLAN */ #ifdef CONFIG_AP_WOWLAN if (pwrctl->wowlan_ap_mode == _TRUE) rtw_hal_set_ap_rsvdpage_loc_cmd(adapter, &RsvdPageLoc); #endif /* CONFIG_AP_WOWLAN */ } else if (pwrctl->wowlan_pno_enable) { #ifdef CONFIG_PNO_SUPPORT rtw_hal_set_FwAoacRsvdPage_cmd(adapter, &RsvdPageLoc); if (pwrctl->wowlan_in_resume) rtw_hal_set_scan_offload_info_cmd(adapter, &RsvdPageLoc, 0); else rtw_hal_set_scan_offload_info_cmd(adapter, &RsvdPageLoc, 1); #endif /* CONFIG_PNO_SUPPORT */ } #ifdef CONFIG_P2P_WOWLAN if (_TRUE == pwrctl->wowlan_p2p_mode) rtw_hal_set_FwP2PRsvdPage_cmd(adapter, &RsvdPageLoc); #endif /* CONFIG_P2P_WOWLAN */ return; error: rtw_free_xmitframe(pxmitpriv, pcmdframe); } void rtw_hal_set_fw_rsvd_page(struct _ADAPTER *adapter, bool finished) { _rtw_hal_set_fw_rsvd_page(adapter, finished, NULL); } /** * rtw_hal_get_rsvd_page_num() - Get needed reserved page number * @adapter: struct _ADAPTER* * * Caculate needed reserved page number. * In different state would get different number, for example normal mode and * WOW mode would need different reserved page size. * * Return the number of reserved page which driver need. */ u8 rtw_hal_get_rsvd_page_num(struct _ADAPTER *adapter) { u8 num = 0; _rtw_hal_set_fw_rsvd_page(adapter, _FALSE, &num); return num; } static void hw_var_set_mlme_sitesurvey(_adapter *adapter, u8 variable, u8 *val) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); u16 value_rxfltmap2; int i; _adapter *iface; #ifdef DBG_IFACE_STATUS DBG_IFACE_STATUS_DUMP(adapter); #endif #ifdef CONFIG_FIND_BEST_CHANNEL /* Receive all data frames */ value_rxfltmap2 = 0xFFFF; #else /* not to receive data frame */ value_rxfltmap2 = 0; #endif if (*((u8 *)val)) { /* under sitesurvey */ /* * 1. configure REG_RXFLTMAP2 * 2. disable TSF update & buddy TSF update to avoid updating wrong TSF due to clear RCR_CBSSID_BCN * 3. config RCR to receive different BSSID BCN or probe rsp */ rtw_write16(adapter, REG_RXFLTMAP2, value_rxfltmap2); #ifdef CONFIG_MI_WITH_MBSSID_CAM /*do nothing~~*/ #else /* disable update TSF */ for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->padapters[i]; if (!iface) continue; if (rtw_linked_check(iface) && !MLME_IS_AP(iface) && !MLME_IS_MESH(iface) ) { if (iface->hw_port == HW_PORT1) rtw_write8(iface, REG_BCN_CTRL_1, rtw_read8(iface, REG_BCN_CTRL_1) | DIS_TSF_UDT); else rtw_write8(iface, REG_BCN_CTRL, rtw_read8(iface, REG_BCN_CTRL) | DIS_TSF_UDT); iface->mlmeextpriv.en_hw_update_tsf = _FALSE; } } #endif /* CONFIG_MI_WITH_MBSSID_CAM */ rtw_hal_rcr_set_chk_bssid(adapter, MLME_SCAN_ENTER); /* Save orignal RRSR setting. needed? */ hal_data->RegRRSR = rtw_read16(adapter, REG_RRSR); #if defined(CONFIG_BEAMFORMING) && (defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A)) if (IS_8812_SERIES(hal_data->version_id) || IS_8821_SERIES(hal_data->version_id)) { /* set 718[1:0]=2'b00 to avoid BF scan hang */ hal_data->backup_snd_ptcl_ctrl = rtw_read8(adapter, REG_SND_PTCL_CTRL_8812A); rtw_write8(adapter, REG_SND_PTCL_CTRL_8812A, (hal_data->backup_snd_ptcl_ctrl & 0xfc)); } #endif if (rtw_mi_get_ap_num(adapter) || rtw_mi_get_mesh_num(adapter)) StopTxBeacon(adapter); } else { /* sitesurvey done */ /* * 1. enable rx data frame * 2. config RCR not to receive different BSSID BCN or probe rsp * 3. doesn't enable TSF update & buddy TSF right now to avoid HW conflict * so, we enable TSF update when rx first BCN after sitesurvey done */ if (rtw_mi_check_fwstate(adapter, _FW_LINKED | WIFI_AP_STATE | WIFI_MESH_STATE)) { /* enable to rx data frame */ rtw_write16(adapter, REG_RXFLTMAP2, 0xFFFF); } rtw_hal_rcr_set_chk_bssid(adapter, MLME_SCAN_DONE); #ifdef CONFIG_MI_WITH_MBSSID_CAM /*if ((rtw_mi_get_assoced_sta_num(adapter) == 1) && (!rtw_mi_check_status(adapter, MI_AP_MODE))) rtw_write8(adapter, REG_BCN_CTRL, rtw_read8(adapter, REG_BCN_CTRL)&(~DIS_TSF_UDT));*/ #else for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->padapters[i]; if (!iface) continue; if (rtw_linked_check(iface) && !MLME_IS_AP(iface) && !MLME_IS_MESH(iface) ) { /* enable HW TSF update when recive beacon*/ /*if (iface->hw_port == HW_PORT1) rtw_write8(iface, REG_BCN_CTRL_1, rtw_read8(iface, REG_BCN_CTRL_1)&(~(DIS_TSF_UDT))); else rtw_write8(iface, REG_BCN_CTRL, rtw_read8(iface, REG_BCN_CTRL)&(~(DIS_TSF_UDT))); */ iface->mlmeextpriv.en_hw_update_tsf = _TRUE; } } #endif /* CONFIG_MI_WITH_MBSSID_CAM */ /* Restore orignal RRSR setting. needed? */ rtw_write16(adapter, REG_RRSR, hal_data->RegRRSR); #if defined(CONFIG_BEAMFORMING) && (defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A)) if (IS_8812_SERIES(hal_data->version_id) || IS_8821_SERIES(hal_data->version_id)) { /* Restore orignal 0x718 setting*/ rtw_write8(adapter, REG_SND_PTCL_CTRL_8812A, hal_data->backup_snd_ptcl_ctrl); } #endif if (rtw_mi_get_ap_num(adapter) || rtw_mi_get_mesh_num(adapter)) { ResumeTxBeacon(adapter); rtw_mi_tx_beacon_hdl(adapter); } } } #ifdef CONFIG_TSF_RESET_OFFLOAD static int rtw_hal_h2c_reset_tsf(_adapter *adapter, u8 reset_port) { u8 buf[2]; int ret; if (reset_port == HW_PORT0) { buf[0] = 0x1; buf[1] = 0; } else { buf[0] = 0x0; buf[1] = 0x1; } ret = rtw_hal_fill_h2c_cmd(adapter, H2C_RESET_TSF, 2, buf); return ret; } int rtw_hal_reset_tsf(_adapter *adapter, u8 reset_port) { u8 reset_cnt_before = 0, reset_cnt_after = 0, loop_cnt = 0; u32 reg_reset_tsf_cnt = (reset_port == HW_PORT0) ? REG_FW_RESET_TSF_CNT_0 : REG_FW_RESET_TSF_CNT_1; int ret; /* site survey will cause reset tsf fail */ rtw_mi_buddy_scan_abort(adapter, _FALSE); reset_cnt_after = reset_cnt_before = rtw_read8(adapter, reg_reset_tsf_cnt); ret = rtw_hal_h2c_reset_tsf(adapter, reset_port); if (ret != _SUCCESS) return ret; while ((reset_cnt_after == reset_cnt_before) && (loop_cnt < 10)) { rtw_msleep_os(100); loop_cnt++; reset_cnt_after = rtw_read8(adapter, reg_reset_tsf_cnt); } return (loop_cnt >= 10) ? _FAIL : _SUCCESS; } #endif /* CONFIG_TSF_RESET_OFFLOAD */ static void rtw_hal_set_hw_update_tsf(PADAPTER padapter) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; #if defined(CONFIG_RTL8822B) || defined(CONFIG_MI_WITH_MBSSID_CAM) RTW_INFO("[Warn] %s "ADPT_FMT" enter func\n", __func__, ADPT_ARG(padapter)); rtw_warn_on(1); return; #endif if (!pmlmeext->en_hw_update_tsf) return; /* check RCR */ if (!rtw_hal_rcr_check(padapter, RCR_CBSSID_BCN)) return; /* enable hw update tsf function for non-AP and non-Mesh */ if (rtw_linked_check(padapter) && !MLME_IS_AP(padapter) && !MLME_IS_MESH(padapter) ) { #ifdef CONFIG_CONCURRENT_MODE if (padapter->hw_port == HW_PORT1) rtw_write8(padapter, REG_BCN_CTRL_1, rtw_read8(padapter, REG_BCN_CTRL_1) & (~DIS_TSF_UDT)); else #endif rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL) & (~DIS_TSF_UDT)); } pmlmeext->en_hw_update_tsf = _FALSE; } static void hw_var_set_correct_tsf(_adapter *adapter) { #ifdef CONFIG_MI_WITH_MBSSID_CAM /*do nothing*/ #else u64 tsf; struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; struct mlme_ext_info *mlmeinfo = &(mlmeext->mlmext_info); tsf = mlmeext->TSFValue - rtw_modular64(mlmeext->TSFValue, (mlmeinfo->bcn_interval * 1024)) - 1024; /*us*/ if ((mlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE || (mlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) StopTxBeacon(adapter); rtw_hal_correct_tsf(adapter, adapter->hw_port, tsf); #ifdef CONFIG_CONCURRENT_MODE /* Update buddy port's TSF if it is SoftAP/Mesh for beacon TX issue! */ if ((mlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE && (rtw_mi_get_ap_num(adapter) || rtw_mi_get_mesh_num(adapter)) ) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); int i; _adapter *iface; for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->padapters[i]; if (!iface) continue; if (iface == adapter) continue; if ((MLME_IS_AP(iface) || MLME_IS_MESH(iface)) && check_fwstate(&iface->mlmepriv, WIFI_ASOC_STATE) == _TRUE ) { rtw_hal_correct_tsf(iface, iface->hw_port, tsf); #ifdef CONFIG_TSF_RESET_OFFLOAD if (rtw_hal_reset_tsf(iface, iface->hw_port) == _FAIL) RTW_INFO("%s-[ERROR] "ADPT_FMT" Reset port%d TSF fail\n" , __func__, ADPT_ARG(iface), iface->hw_port); #endif /* CONFIG_TSF_RESET_OFFLOAD*/ } } } #endif /* CONFIG_CONCURRENT_MODE */ if ((mlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE || (mlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) ResumeTxBeacon(adapter); #endif /*CONFIG_MI_WITH_MBSSID_CAM*/ } #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_CH_SW s32 rtw_hal_ch_sw_oper_offload(_adapter *padapter, u8 channel, u8 channel_offset, u16 bwmode) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); u8 ch_sw_h2c_buf[4] = {0x00, 0x00, 0x00, 0x00}; SET_H2CCMD_CH_SW_OPER_OFFLOAD_CH_NUM(ch_sw_h2c_buf, channel); SET_H2CCMD_CH_SW_OPER_OFFLOAD_BW_MODE(ch_sw_h2c_buf, bwmode); switch (bwmode) { case CHANNEL_WIDTH_40: SET_H2CCMD_CH_SW_OPER_OFFLOAD_BW_40M_SC(ch_sw_h2c_buf, channel_offset); break; case CHANNEL_WIDTH_80: SET_H2CCMD_CH_SW_OPER_OFFLOAD_BW_80M_SC(ch_sw_h2c_buf, channel_offset); break; case CHANNEL_WIDTH_20: default: break; } SET_H2CCMD_CH_SW_OPER_OFFLOAD_RFE_TYPE(ch_sw_h2c_buf, pHalData->rfe_type); return rtw_hal_fill_h2c_cmd(padapter, H2C_CHNL_SWITCH_OPER_OFFLOAD, sizeof(ch_sw_h2c_buf), ch_sw_h2c_buf); } #endif #endif #ifdef CONFIG_WMMPS_STA void rtw_hal_update_uapsd_tid(_adapter *adapter) { struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct qos_priv *pqospriv = &pmlmepriv->qospriv; /* write complement of pqospriv->uapsd_tid to mac register 0x693 because it's designed for "0" represents "enable" and "1" represents "disable" */ rtw_write8(adapter, REG_WMMPS_UAPSD_TID, (u8)(~pqospriv->uapsd_tid)); } #endif /* CONFIG_WMMPS_STA */ #if defined(CONFIG_BT_COEXIST) && defined(CONFIG_FW_MULTI_PORT_SUPPORT) /* For multi-port support, driver needs to inform the port ID to FW for btc operations */ s32 rtw_hal_set_wifi_port_id_cmd(_adapter *adapter) { u8 port_id = 0; u8 h2c_buf[H2C_BTC_WL_PORT_ID_LEN] = {0}; SET_H2CCMD_BTC_WL_PORT_ID(h2c_buf, adapter->hw_port); return rtw_hal_fill_h2c_cmd(adapter, H2C_BTC_WL_PORT_ID, H2C_BTC_WL_PORT_ID_LEN, h2c_buf); } #endif u8 SetHwReg(_adapter *adapter, u8 variable, u8 *val) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); u8 ret = _SUCCESS; switch (variable) { case HW_VAR_MEDIA_STATUS: { u8 net_type = *((u8 *)val); rtw_hal_set_msr(adapter, net_type); } break; case HW_VAR_MAC_ADDR: #ifdef CONFIG_MI_WITH_MBSSID_CAM rtw_hal_set_macaddr_mbid(adapter, val); #else rtw_hal_set_macaddr_port(adapter, val); #endif break; case HW_VAR_BSSID: rtw_hal_set_bssid(adapter, val); break; case HW_VAR_RCR: ret = hw_var_rcr_config(adapter, *((u32 *)val)); break; case HW_VAR_ON_RCR_AM: hw_var_set_rcr_am(adapter, 1); break; case HW_VAR_OFF_RCR_AM: hw_var_set_rcr_am(adapter, 0); break; case HW_VAR_BEACON_INTERVAL: hw_var_set_bcn_interval(adapter, *(u16 *)val); break; #ifdef CONFIG_MBSSID_CAM case HW_VAR_MBSSID_CAM_WRITE: { u32 cmd = 0; u32 *cam_val = (u32 *)val; rtw_write32(adapter, REG_MBIDCAMCFG_1, cam_val[0]); cmd = BIT_MBIDCAM_POLL | BIT_MBIDCAM_WT_EN | BIT_MBIDCAM_VALID | cam_val[1]; rtw_write32(adapter, REG_MBIDCAMCFG_2, cmd); } break; case HW_VAR_MBSSID_CAM_CLEAR: { u32 cmd; u8 entry_id = *(u8 *)val; rtw_write32(adapter, REG_MBIDCAMCFG_1, 0); cmd = BIT_MBIDCAM_POLL | BIT_MBIDCAM_WT_EN | ((entry_id & MBIDCAM_ADDR_MASK) << MBIDCAM_ADDR_SHIFT); rtw_write32(adapter, REG_MBIDCAMCFG_2, cmd); } break; case HW_VAR_RCR_MBSSID_EN: if (*((u8 *)val)) rtw_hal_rcr_add(adapter, RCR_ENMBID); else rtw_hal_rcr_clear(adapter, RCR_ENMBID); break; #endif case HW_VAR_PORT_SWITCH: hw_var_port_switch(adapter); break; case HW_VAR_INIT_RTS_RATE: { u16 brate_cfg = *((u16 *)val); u8 rate_index = 0; HAL_VERSION *hal_ver = &hal_data->version_id; if (IS_8188E(*hal_ver)) { while (brate_cfg > 0x1) { brate_cfg = (brate_cfg >> 1); rate_index++; } rtw_write8(adapter, REG_INIRTS_RATE_SEL, rate_index); } else rtw_warn_on(1); } break; case HW_VAR_SEC_CFG: { u16 reg_scr_ori; u16 reg_scr; reg_scr = reg_scr_ori = rtw_read16(adapter, REG_SECCFG); reg_scr |= (SCR_CHK_KEYID | SCR_RxDecEnable | SCR_TxEncEnable); if (_rtw_camctl_chk_cap(adapter, SEC_CAP_CHK_BMC)) reg_scr |= SCR_CHK_BMC; if (_rtw_camctl_chk_flags(adapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH)) reg_scr |= SCR_NoSKMC; if (reg_scr != reg_scr_ori) rtw_write16(adapter, REG_SECCFG, reg_scr); } break; case HW_VAR_SEC_DK_CFG: { struct security_priv *sec = &adapter->securitypriv; u8 reg_scr = rtw_read8(adapter, REG_SECCFG); if (val) { /* Enable default key related setting */ reg_scr |= SCR_TXBCUSEDK; if (sec->dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) reg_scr |= (SCR_RxUseDK | SCR_TxUseDK); } else /* Disable default key related setting */ reg_scr &= ~(SCR_RXBCUSEDK | SCR_TXBCUSEDK | SCR_RxUseDK | SCR_TxUseDK); rtw_write8(adapter, REG_SECCFG, reg_scr); } break; case HW_VAR_ASIX_IOT: /* enable ASIX IOT function */ if (*((u8 *)val) == _TRUE) { /* 0xa2e[0]=0 (disable rake receiver) */ rtw_write8(adapter, rCCK0_FalseAlarmReport + 2, rtw_read8(adapter, rCCK0_FalseAlarmReport + 2) & ~(BIT0)); /* 0xa1c=0xa0 (reset channel estimation if signal quality is bad) */ rtw_write8(adapter, rCCK0_DSPParameter2, 0xa0); } else { /* restore reg:0xa2e, reg:0xa1c */ rtw_write8(adapter, rCCK0_FalseAlarmReport + 2, rtw_read8(adapter, rCCK0_FalseAlarmReport + 2) | (BIT0)); rtw_write8(adapter, rCCK0_DSPParameter2, 0x00); } break; #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) case HW_VAR_WOWLAN: { struct wowlan_ioctl_param *poidparam; poidparam = (struct wowlan_ioctl_param *)val; switch (poidparam->subcode) { #ifdef CONFIG_WOWLAN case WOWLAN_PATTERN_CLEAN: rtw_hal_dl_pattern(adapter, 2); break; case WOWLAN_ENABLE: rtw_hal_wow_enable(adapter); break; case WOWLAN_DISABLE: rtw_hal_wow_disable(adapter); break; #endif /*CONFIG_WOWLAN*/ #ifdef CONFIG_AP_WOWLAN case WOWLAN_AP_ENABLE: rtw_hal_ap_wow_enable(adapter); break; case WOWLAN_AP_DISABLE: rtw_hal_ap_wow_disable(adapter); break; #endif /*CONFIG_AP_WOWLAN*/ default: break; } } break; #endif /*defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)*/ case HW_VAR_MLME_SITESURVEY: hw_var_set_mlme_sitesurvey(adapter, variable, val); #ifdef CONFIG_BT_COEXIST if (hal_data->EEPROMBluetoothCoexist == 1) rtw_btcoex_ScanNotify(adapter, *val ? _TRUE : _FALSE); #endif break; case HW_VAR_EN_HW_UPDATE_TSF: rtw_hal_set_hw_update_tsf(adapter); break; case HW_VAR_CORRECT_TSF: hw_var_set_correct_tsf(adapter); break; case HW_VAR_APFM_ON_MAC: hal_data->bMacPwrCtrlOn = *val; RTW_INFO("%s: bMacPwrCtrlOn=%d\n", __func__, hal_data->bMacPwrCtrlOn); break; #ifdef CONFIG_WMMPS_STA case HW_VAR_UAPSD_TID: rtw_hal_update_uapsd_tid(adapter); break; #endif /* CONFIG_WMMPS_STA */ #ifdef CONFIG_LPS_PG case HW_VAR_LPS_PG_HANDLE: rtw_hal_lps_pg_handler(adapter, *val); break; #endif #ifdef CONFIG_LPS_LCLK_WD_TIMER case HW_VAR_DM_IN_LPS_LCLK: rtw_phydm_wd_lps_lclk_hdl(adapter); break; #endif case HW_VAR_ENABLE_RX_BAR: if (*val == _TRUE) { /* enable RX BAR */ u16 val16 = rtw_read16(adapter, REG_RXFLTMAP1); val16 |= BIT(8); rtw_write16(adapter, REG_RXFLTMAP1, val16); } else { /* disable RX BAR */ u16 val16 = rtw_read16(adapter, REG_RXFLTMAP1); val16 &= (~BIT(8)); rtw_write16(adapter, REG_RXFLTMAP1, val16); } RTW_INFO("[HW_VAR_ENABLE_RX_BAR] 0x%02X=0x%02X\n", REG_RXFLTMAP1, rtw_read16(adapter, REG_RXFLTMAP1)); break; default: if (0) RTW_PRINT(FUNC_ADPT_FMT" variable(%d) not defined!\n", FUNC_ADPT_ARG(adapter), variable); ret = _FAIL; break; } return ret; } void GetHwReg(_adapter *adapter, u8 variable, u8 *val) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); u64 val64; switch (variable) { case HW_VAR_MAC_ADDR: rtw_hal_get_macaddr_port(adapter, val); break; case HW_VAR_BASIC_RATE: *((u16 *)val) = hal_data->BasicRateSet; break; case HW_VAR_RF_TYPE: *((u8 *)val) = hal_data->rf_type; break; case HW_VAR_MEDIA_STATUS: rtw_hal_get_msr(adapter, val); break; case HW_VAR_DO_IQK: *val = hal_data->bNeedIQK; break; case HW_VAR_CH_SW_NEED_TO_TAKE_CARE_IQK_INFO: if (hal_is_band_support(adapter, BAND_ON_5G)) *val = _TRUE; else *val = _FALSE; break; case HW_VAR_APFM_ON_MAC: *val = hal_data->bMacPwrCtrlOn; break; case HW_VAR_RCR: hw_var_rcr_get(adapter, (u32 *)val); break; case HW_VAR_FWLPS_RF_ON: /* When we halt NIC, we should check if FW LPS is leave. */ if (rtw_is_surprise_removed(adapter) || (adapter_to_pwrctl(adapter)->rf_pwrstate == rf_off) ) { /* * If it is in HW/SW Radio OFF or IPS state, * we do not check Fw LPS Leave, * because Fw is unload. */ *val = _TRUE; } else { u32 rcr = 0; rtw_hal_get_hwreg(adapter, HW_VAR_RCR, (u8 *)&rcr); if (rcr & (RCR_UC_MD_EN | RCR_BC_MD_EN | RCR_TIM_PARSER_EN)) *val = _FALSE; else *val = _TRUE; } break; case HW_VAR_TSF: /* read and save HIGH 32bits TSF value */ val64 = rtw_read32(adapter, REG_TSFTR+4); val64 = val64 << 32; /* read and save LOW 32bits TSF value */ val64 |= rtw_read32(adapter, REG_TSFTR); *((u64*)val) = val64; break; default: if (0) RTW_PRINT(FUNC_ADPT_FMT" variable(%d) not defined!\n", FUNC_ADPT_ARG(adapter), variable); break; } } static u32 _get_page_size(struct _ADAPTER *a) { #ifdef RTW_HALMAC struct dvobj_priv *d; u32 size = 0; int err = 0; d = adapter_to_dvobj(a); err = rtw_halmac_get_page_size(d, &size); if (!err) return size; RTW_WARN(FUNC_ADPT_FMT ": Fail to get Page size!!(err=%d)\n", FUNC_ADPT_ARG(a), err); #endif /* RTW_HALMAC */ return PAGE_SIZE_128; } u8 SetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); u8 bResult = _SUCCESS; switch (variable) { case HAL_DEF_DBG_DUMP_RXPKT: hal_data->bDumpRxPkt = *((u8 *)value); break; case HAL_DEF_DBG_DUMP_TXPKT: hal_data->bDumpTxPkt = *((u8 *)value); break; case HAL_DEF_ANT_DETECT: hal_data->AntDetection = *((u8 *)value); break; default: RTW_PRINT("%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __FUNCTION__, variable); bResult = _FAIL; break; } return bResult; } #ifdef CONFIG_BEAMFORMING u8 rtw_hal_query_txbfer_rf_num(_adapter *adapter) { struct registry_priv *pregistrypriv = &adapter->registrypriv; HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); if ((pregistrypriv->beamformer_rf_num) && (IS_HARDWARE_TYPE_8814AE(adapter) || IS_HARDWARE_TYPE_8814AU(adapter) || IS_HARDWARE_TYPE_8822BU(adapter) || IS_HARDWARE_TYPE_8821C(adapter))) return pregistrypriv->beamformer_rf_num; else if (IS_HARDWARE_TYPE_8814AE(adapter) #if 0 #if defined(CONFIG_USB_HCI) || (IS_HARDWARE_TYPE_8814AU(adapter) && (pUsbModeMech->CurUsbMode == 2 || pUsbModeMech->HubUsbMode == 2)) /* for USB3.0 */ #endif #endif ) { /*BF cap provided by Yu Chen, Sean, 2015, 01 */ if (hal_data->rf_type == RF_3T3R) return 2; else if (hal_data->rf_type == RF_4T4R) return 3; else return 1; } else return 1; } u8 rtw_hal_query_txbfee_rf_num(_adapter *adapter) { struct registry_priv *pregistrypriv = &adapter->registrypriv; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); if ((pregistrypriv->beamformee_rf_num) && (IS_HARDWARE_TYPE_8814AE(adapter) || IS_HARDWARE_TYPE_8814AU(adapter) || IS_HARDWARE_TYPE_8822BU(adapter) || IS_HARDWARE_TYPE_8821C(adapter))) return pregistrypriv->beamformee_rf_num; else if (IS_HARDWARE_TYPE_8814AE(adapter) || IS_HARDWARE_TYPE_8814AU(adapter)) { if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) return 2; else return 2;/*TODO: May be 3 in the future, by ChenYu. */ } else return 1; } #ifdef RTW_BEAMFORMING_VERSION_2 void rtw_hal_beamforming_config_csirate(PADAPTER adapter) { struct dm_struct *p_dm_odm; struct beamforming_info *bf_info; u8 fix_rate_enable = 0; u8 new_csi_rate_idx; /* Acting as BFee */ if (IS_BEAMFORMEE(adapter)) { #if 0 /* Do not enable now because it will affect MU performance and CTS/BA rate. 2016.07.19. by tynli. [PCIE-1660] */ if (IS_HARDWARE_TYPE_8821C(Adapter)) FixRateEnable = 1; /* Support after 8821C */ #endif p_dm_odm = adapter_to_phydm(adapter); bf_info = GET_BEAMFORM_INFO(adapter); rtw_halmac_bf_cfg_csi_rate(adapter_to_dvobj(adapter), p_dm_odm->rssi_min, bf_info->cur_csi_rpt_rate, fix_rate_enable, &new_csi_rate_idx); if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate) bf_info->cur_csi_rpt_rate = new_csi_rate_idx; } } #endif #endif u8 GetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); u8 bResult = _SUCCESS; switch (variable) { case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: { struct mlme_priv *pmlmepriv; struct sta_priv *pstapriv; struct sta_info *psta; pmlmepriv = &adapter->mlmepriv; pstapriv = &adapter->stapriv; psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress); if (psta) *((int *)value) = psta->cmn.rssi_stat.rssi; } break; case HAL_DEF_DBG_DUMP_RXPKT: *((u8 *)value) = hal_data->bDumpRxPkt; break; case HAL_DEF_DBG_DUMP_TXPKT: *((u8 *)value) = hal_data->bDumpTxPkt; break; case HAL_DEF_ANT_DETECT: *((u8 *)value) = hal_data->AntDetection; break; case HAL_DEF_TX_PAGE_SIZE: *((u32 *)value) = _get_page_size(adapter); break; case HAL_DEF_EXPLICIT_BEAMFORMER: case HAL_DEF_EXPLICIT_BEAMFORMEE: case HAL_DEF_VHT_MU_BEAMFORMER: case HAL_DEF_VHT_MU_BEAMFORMEE: *(u8 *)value = _FALSE; break; #ifdef CONFIG_BEAMFORMING case HAL_DEF_BEAMFORMER_CAP: *(u8 *)value = rtw_hal_query_txbfer_rf_num(adapter); break; case HAL_DEF_BEAMFORMEE_CAP: *(u8 *)value = rtw_hal_query_txbfee_rf_num(adapter); break; #endif default: RTW_PRINT("%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __FUNCTION__, variable); bResult = _FAIL; break; } return bResult; } BOOLEAN eqNByte( u8 *str1, u8 *str2, u32 num ) { if (num == 0) return _FALSE; while (num > 0) { num--; if (str1[num] != str2[num]) return _FALSE; } return _TRUE; } /* * Description: * Translate a character to hex digit. * */ u32 MapCharToHexDigit( IN char chTmp ) { if (chTmp >= '0' && chTmp <= '9') return chTmp - '0'; else if (chTmp >= 'a' && chTmp <= 'f') return 10 + (chTmp - 'a'); else if (chTmp >= 'A' && chTmp <= 'F') return 10 + (chTmp - 'A'); else return 0; } /* * Description: * Parse hex number from the string pucStr. * */ BOOLEAN GetHexValueFromString( IN char *szStr, IN OUT u32 *pu4bVal, IN OUT u32 *pu4bMove ) { char *szScan = szStr; /* Check input parameter. */ if (szStr == NULL || pu4bVal == NULL || pu4bMove == NULL) { RTW_INFO("GetHexValueFromString(): Invalid inpur argumetns! szStr: %p, pu4bVal: %p, pu4bMove: %p\n", szStr, pu4bVal, pu4bMove); return _FALSE; } /* Initialize output. */ *pu4bMove = 0; *pu4bVal = 0; /* Skip leading space. */ while (*szScan != '\0' && (*szScan == ' ' || *szScan == '\t')) { szScan++; (*pu4bMove)++; } /* Skip leading '0x' or '0X'. */ if (*szScan == '0' && (*(szScan + 1) == 'x' || *(szScan + 1) == 'X')) { szScan += 2; (*pu4bMove) += 2; } /* Check if szScan is now pointer to a character for hex digit, */ /* if not, it means this is not a valid hex number. */ if (!IsHexDigit(*szScan)) return _FALSE; /* Parse each digit. */ do { (*pu4bVal) <<= 4; *pu4bVal += MapCharToHexDigit(*szScan); szScan++; (*pu4bMove)++; } while (IsHexDigit(*szScan)); return _TRUE; } BOOLEAN GetFractionValueFromString( IN char *szStr, IN OUT u8 *pInteger, IN OUT u8 *pFraction, IN OUT u32 *pu4bMove ) { char *szScan = szStr; /* Initialize output. */ *pu4bMove = 0; *pInteger = 0; *pFraction = 0; /* Skip leading space. */ while (*szScan != '\0' && (*szScan == ' ' || *szScan == '\t')) { ++szScan; ++(*pu4bMove); } /* Parse each digit. */ do { (*pInteger) *= 10; *pInteger += (*szScan - '0'); ++szScan; ++(*pu4bMove); if (*szScan == '.') { ++szScan; ++(*pu4bMove); if (*szScan < '0' || *szScan > '9') return _FALSE; else { *pFraction = *szScan - '0'; ++szScan; ++(*pu4bMove); return _TRUE; } } } while (*szScan >= '0' && *szScan <= '9'); return _TRUE; } /* * Description: * Return TRUE if szStr is comment out with leading " */ /* ". * */ BOOLEAN IsCommentString( IN char *szStr ) { if (*szStr == '/' && *(szStr + 1) == '/') return _TRUE; else return _FALSE; } BOOLEAN GetU1ByteIntegerFromStringInDecimal( IN char *Str, IN OUT u8 *pInt ) { u16 i = 0; *pInt = 0; while (Str[i] != '\0') { if (Str[i] >= '0' && Str[i] <= '9') { *pInt *= 10; *pInt += (Str[i] - '0'); } else return _FALSE; ++i; } return _TRUE; } /* <20121004, Kordan> For example, * ParseQualifiedString(inString, 0, outString, '[', ']') gets "Kordan" from a string "Hello [Kordan]". * If RightQualifier does not exist, it will hang on in the while loop */ BOOLEAN ParseQualifiedString( IN char *In, IN OUT u32 *Start, OUT char *Out, IN char LeftQualifier, IN char RightQualifier ) { u32 i = 0, j = 0; char c = In[(*Start)++]; if (c != LeftQualifier) return _FALSE; i = (*Start); c = In[(*Start)++]; while (c != RightQualifier && c != '\0') c = In[(*Start)++]; if (c == '\0') return _FALSE; j = (*Start) - 2; strncpy((char *)Out, (const char *)(In + i), j - i + 1); return _TRUE; } BOOLEAN isAllSpaceOrTab( u8 *data, u8 size ) { u8 cnt = 0, NumOfSpaceAndTab = 0; while (size > cnt) { if (data[cnt] == ' ' || data[cnt] == '\t' || data[cnt] == '\0') ++NumOfSpaceAndTab; ++cnt; } return size == NumOfSpaceAndTab; } void rtw_hal_check_rxfifo_full(_adapter *adapter) { struct dvobj_priv *psdpriv = adapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); struct registry_priv *regsty = &adapter->registrypriv; int save_cnt = _FALSE; if (regsty->check_hw_status == 1) { /* switch counter to RX fifo */ if (IS_8188E(pHalData->version_id) || IS_8188F(pHalData->version_id) || IS_8812_SERIES(pHalData->version_id) || IS_8821_SERIES(pHalData->version_id) || IS_8723B_SERIES(pHalData->version_id) || IS_8192E(pHalData->version_id) || IS_8703B_SERIES(pHalData->version_id) || IS_8723D_SERIES(pHalData->version_id)) { rtw_write8(adapter, REG_RXERR_RPT + 3, rtw_read8(adapter, REG_RXERR_RPT + 3) | 0xa0); save_cnt = _TRUE; } else { /* todo: other chips */ } if (save_cnt) { pdbgpriv->dbg_rx_fifo_last_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow; pdbgpriv->dbg_rx_fifo_curr_overflow = rtw_read16(adapter, REG_RXERR_RPT); pdbgpriv->dbg_rx_fifo_diff_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow - pdbgpriv->dbg_rx_fifo_last_overflow; } else { /* special value to indicate no implementation */ pdbgpriv->dbg_rx_fifo_last_overflow = 1; pdbgpriv->dbg_rx_fifo_curr_overflow = 1; pdbgpriv->dbg_rx_fifo_diff_overflow = 1; } } } void linked_info_dump(_adapter *padapter, u8 benable) { struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); if (padapter->bLinkInfoDump == benable) return; RTW_INFO("%s %s\n", __FUNCTION__, (benable) ? "enable" : "disable"); if (benable) { #ifdef CONFIG_LPS pwrctrlpriv->org_power_mgnt = pwrctrlpriv->power_mgnt;/* keep org value */ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); #endif #ifdef CONFIG_IPS pwrctrlpriv->ips_org_mode = pwrctrlpriv->ips_mode;/* keep org value */ rtw_pm_set_ips(padapter, IPS_NONE); #endif } else { #ifdef CONFIG_IPS rtw_pm_set_ips(padapter, pwrctrlpriv->ips_org_mode); #endif /* CONFIG_IPS */ #ifdef CONFIG_LPS rtw_pm_set_lps(padapter, pwrctrlpriv->org_power_mgnt); #endif /* CONFIG_LPS */ } padapter->bLinkInfoDump = benable ; } #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA void rtw_get_raw_rssi_info(void *sel, _adapter *padapter) { u8 isCCKrate, rf_path; PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; RTW_PRINT_SEL(sel, "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", HDATA_RATE(psample_pkt_rssi->data_rate), psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); isCCKrate = (psample_pkt_rssi->data_rate <= DESC_RATE11M) ? TRUE : FALSE; if (isCCKrate) psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball; for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { RTW_PRINT_SEL(sel, "RF_PATH_%d=>signal_strength:%d(%%),signal_quality:%d(%%)\n" , rf_path, psample_pkt_rssi->mimo_signal_strength[rf_path], psample_pkt_rssi->mimo_signal_quality[rf_path]); if (!isCCKrate) { RTW_PRINT_SEL(sel, "\trx_ofdm_pwr:%d(dBm),rx_ofdm_snr:%d(dB)\n", psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]); } } } void rtw_dump_raw_rssi_info(_adapter *padapter, void *sel) { u8 isCCKrate, rf_path; PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; _RTW_PRINT_SEL(sel, "============ RAW Rx Info dump ===================\n"); _RTW_PRINT_SEL(sel, "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", HDATA_RATE(psample_pkt_rssi->data_rate), psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); isCCKrate = (psample_pkt_rssi->data_rate <= DESC_RATE11M) ? TRUE : FALSE; if (isCCKrate) psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball; for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { _RTW_PRINT_SEL(sel , "RF_PATH_%d=>signal_strength:%d(%%),signal_quality:%d(%%)" , rf_path, psample_pkt_rssi->mimo_signal_strength[rf_path], psample_pkt_rssi->mimo_signal_quality[rf_path]); if (!isCCKrate) _RTW_PRINT_SEL(sel , ",rx_ofdm_pwr:%d(dBm),rx_ofdm_snr:%d(dB)\n", psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]); else _RTW_PRINT_SEL(sel , "\n"); } } #endif #ifdef DBG_RX_DFRAME_RAW_DATA void rtw_dump_rx_dframe_info(_adapter *padapter, void *sel) { #define DBG_RX_DFRAME_RAW_DATA_UC 0 #define DBG_RX_DFRAME_RAW_DATA_BMC 1 #define DBG_RX_DFRAME_RAW_DATA_TYPES 2 _irqL irqL; u8 isCCKrate, rf_path; struct recv_priv *precvpriv = &(padapter->recvpriv); PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); struct sta_priv *pstapriv = &padapter->stapriv; struct sta_info *psta; struct sta_recv_dframe_info *psta_dframe_info; int i, j; _list *plist, *phead; u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (precvpriv->store_law_data_flag) { _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); for (i = 0; i < NUM_STA; i++) { phead = &(pstapriv->sta_hash[i]); plist = get_next(phead); while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); plist = get_next(plist); if (psta) { if ((_rtw_memcmp(psta->cmn.mac_addr, bc_addr, 6) != _TRUE) && (_rtw_memcmp(psta->cmn.mac_addr, null_addr, 6) != _TRUE) && (_rtw_memcmp(psta->cmn.mac_addr, adapter_mac_addr(padapter), 6) != _TRUE)) { RTW_PRINT_SEL(sel, "==============================\n"); RTW_PRINT_SEL(sel, "macaddr =" MAC_FMT "\n", MAC_ARG(psta->cmn.mac_addr)); for (j = 0; j < DBG_RX_DFRAME_RAW_DATA_TYPES; j++) { if (j == DBG_RX_DFRAME_RAW_DATA_UC) { psta_dframe_info = &psta->sta_dframe_info; RTW_PRINT_SEL(sel, "\n"); RTW_PRINT_SEL(sel, "Unicast:\n"); } else if (j == DBG_RX_DFRAME_RAW_DATA_BMC) { psta_dframe_info = &psta->sta_dframe_info_bmc; RTW_PRINT_SEL(sel, "\n"); RTW_PRINT_SEL(sel, "Broadcast/Multicast:\n"); } isCCKrate = (psta_dframe_info->sta_data_rate <= DESC_RATE11M) ? TRUE : FALSE; RTW_PRINT_SEL(sel, "BW=%s, sgi =%d\n", ch_width_str(psta_dframe_info->sta_bw_mode), psta_dframe_info->sta_sgi); RTW_PRINT_SEL(sel, "Rx_Data_Rate = %s\n", HDATA_RATE(psta_dframe_info->sta_data_rate)); for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { if (!isCCKrate) { RTW_PRINT_SEL(sel , "RF_PATH_%d RSSI:%d(dBm)", rf_path, psta_dframe_info->sta_RxPwr[rf_path]); _RTW_PRINT_SEL(sel , ",rx_ofdm_snr:%d(dB)\n", psta_dframe_info->sta_ofdm_snr[rf_path]); } else RTW_PRINT_SEL(sel , "RF_PATH_%d RSSI:%d(dBm)\n", rf_path, (psta_dframe_info->sta_mimo_signal_strength[rf_path]) - 100); } } } } } } _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); } } #endif void rtw_store_phy_info(_adapter *padapter, union recv_frame *prframe) { u8 isCCKrate, rf_path , dframe_type; u8 *ptr; u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; #ifdef DBG_RX_DFRAME_RAW_DATA struct sta_recv_dframe_info *psta_dframe_info; #endif struct recv_priv *precvpriv = &(padapter->recvpriv); PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; struct sta_info *psta = prframe->u.hdr.psta; struct phydm_phyinfo_struct *p_phy_info = &pattrib->phy_info; struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; psample_pkt_rssi->data_rate = pattrib->data_rate; ptr = prframe->u.hdr.rx_data; dframe_type = GetFrameType(ptr); /*RTW_INFO("=>%s\n", __FUNCTION__);*/ if (precvpriv->store_law_data_flag) { isCCKrate = (pattrib->data_rate <= DESC_RATE11M) ? TRUE : FALSE; psample_pkt_rssi->pwdball = p_phy_info->rx_pwdb_all; psample_pkt_rssi->pwr_all = p_phy_info->recv_signal_power; for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { psample_pkt_rssi->mimo_signal_strength[rf_path] = p_phy_info->rx_mimo_signal_strength[rf_path]; psample_pkt_rssi->mimo_signal_quality[rf_path] = p_phy_info->rx_mimo_signal_quality[rf_path]; if (!isCCKrate) { psample_pkt_rssi->ofdm_pwr[rf_path] = p_phy_info->rx_pwr[rf_path]; psample_pkt_rssi->ofdm_snr[rf_path] = p_phy_info->rx_snr[rf_path]; } } #ifdef DBG_RX_DFRAME_RAW_DATA if ((dframe_type == WIFI_DATA_TYPE) || (dframe_type == WIFI_QOS_DATA_TYPE) || (padapter->registrypriv.mp_mode == 1)) { /*RTW_INFO("=>%s WIFI_DATA_TYPE or WIFI_QOS_DATA_TYPE\n", __FUNCTION__);*/ if (psta) { if (IS_MCAST(get_ra(get_recvframe_data(prframe)))) psta_dframe_info = &psta->sta_dframe_info_bmc; else psta_dframe_info = &psta->sta_dframe_info; /*RTW_INFO("=>%s psta->cmn.mac_addr="MAC_FMT" !\n", __FUNCTION__, MAC_ARG(psta->cmn.mac_addr));*/ if ((_rtw_memcmp(psta->cmn.mac_addr, bc_addr, ETH_ALEN) != _TRUE) || (padapter->registrypriv.mp_mode == 1)) { psta_dframe_info->sta_data_rate = pattrib->data_rate; psta_dframe_info->sta_sgi = pattrib->sgi; psta_dframe_info->sta_bw_mode = pattrib->bw; for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { psta_dframe_info->sta_mimo_signal_strength[rf_path] = (p_phy_info->rx_mimo_signal_strength[rf_path]);/*Percentage to dbm*/ if (!isCCKrate) { psta_dframe_info->sta_ofdm_snr[rf_path] = p_phy_info->rx_snr[rf_path]; psta_dframe_info->sta_RxPwr[rf_path] = p_phy_info->rx_pwr[rf_path]; } } } } } #endif } } int hal_efuse_macaddr_offset(_adapter *adapter) { u8 interface_type = 0; int addr_offset = -1; interface_type = rtw_get_intf_type(adapter); switch (rtw_get_chip_type(adapter)) { #ifdef CONFIG_RTL8723B case RTL8723B: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8723BU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8723BS; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8723BE; break; #endif #ifdef CONFIG_RTL8703B case RTL8703B: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8703BU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8703BS; break; #endif #ifdef CONFIG_RTL8723D case RTL8723D: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8723DU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8723DS; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8723DE; break; #endif #ifdef CONFIG_RTL8188E case RTL8188E: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_88EU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_88ES; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_88EE; break; #endif #ifdef CONFIG_RTL8188F case RTL8188F: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8188FU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8188FS; break; #endif #ifdef CONFIG_RTL8812A case RTL8812: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8812AU; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8812AE; break; #endif #ifdef CONFIG_RTL8821A case RTL8821: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8821AU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8821AS; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8821AE; break; #endif #ifdef CONFIG_RTL8192E case RTL8192E: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8192EU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8192ES; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8192EE; break; #endif #ifdef CONFIG_RTL8814A case RTL8814A: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8814AU; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8814AE; break; #endif #ifdef CONFIG_RTL8822B case RTL8822B: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8822BU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8822BS; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8822BE; break; #endif /* CONFIG_RTL8822B */ #ifdef CONFIG_RTL8821C case RTL8821C: if (interface_type == RTW_USB) addr_offset = EEPROM_MAC_ADDR_8821CU; else if (interface_type == RTW_SDIO) addr_offset = EEPROM_MAC_ADDR_8821CS; else if (interface_type == RTW_PCIE) addr_offset = EEPROM_MAC_ADDR_8821CE; break; #endif /* CONFIG_RTL8821C */ } if (addr_offset == -1) { RTW_ERR("%s: unknown combination - chip_type:%u, interface:%u\n" , __func__, rtw_get_chip_type(adapter), rtw_get_intf_type(adapter)); } return addr_offset; } int Hal_GetPhyEfuseMACAddr(PADAPTER padapter, u8 *mac_addr) { int ret = _FAIL; int addr_offset; addr_offset = hal_efuse_macaddr_offset(padapter); if (addr_offset == -1) goto exit; ret = rtw_efuse_map_read(padapter, addr_offset, ETH_ALEN, mac_addr); exit: return ret; } void rtw_dump_cur_efuse(PADAPTER padapter) { int i =0; int mapsize =0; HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&mapsize, _FALSE); if (mapsize <= 0 || mapsize > EEPROM_MAX_SIZE) { RTW_ERR("wrong map size %d\n", mapsize); return; } #ifdef CONFIG_RTW_DEBUG if (hal_data->efuse_file_status == EFUSE_FILE_LOADED) RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "EFUSE FILE", hal_data->efuse_eeprom_data, mapsize); else RTW_MAP_DUMP_SEL(RTW_DBGDUMP, "HW EFUSE", hal_data->efuse_eeprom_data, mapsize); #endif } #ifdef CONFIG_EFUSE_CONFIG_FILE u32 Hal_readPGDataFromConfigFile(PADAPTER padapter) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); u32 ret = _FALSE; u32 maplen = 0; EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&maplen, _FALSE); if (maplen < 256 || maplen > EEPROM_MAX_SIZE) { RTW_ERR("eFuse length error :%d\n", maplen); return _FALSE; } ret = rtw_read_efuse_from_file(EFUSE_MAP_PATH, hal_data->efuse_eeprom_data, maplen); hal_data->efuse_file_status = ((ret == _FAIL) ? EFUSE_FILE_FAILED : EFUSE_FILE_LOADED); if (hal_data->efuse_file_status == EFUSE_FILE_LOADED) rtw_dump_cur_efuse(padapter); return ret; } u32 Hal_ReadMACAddrFromFile(PADAPTER padapter, u8 *mac_addr) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); u32 ret = _FAIL; if (rtw_read_macaddr_from_file(WIFIMAC_PATH, mac_addr) == _SUCCESS && rtw_check_invalid_mac_address(mac_addr, _TRUE) == _FALSE ) { hal_data->macaddr_file_status = MACADDR_FILE_LOADED; ret = _SUCCESS; } else hal_data->macaddr_file_status = MACADDR_FILE_FAILED; return ret; } #endif /* CONFIG_EFUSE_CONFIG_FILE */ int hal_config_macaddr(_adapter *adapter, bool autoload_fail) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); u8 addr[ETH_ALEN]; int addr_offset = hal_efuse_macaddr_offset(adapter); u8 *hw_addr = NULL; int ret = _SUCCESS; #if defined(CONFIG_RTL8822B) && defined(CONFIG_USB_HCI) u8 ft_mac_addr[ETH_ALEN] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; /* FT USB2 for 8822B */ #endif if (autoload_fail) goto bypass_hw_pg; if (addr_offset != -1) hw_addr = &hal_data->efuse_eeprom_data[addr_offset]; #ifdef CONFIG_EFUSE_CONFIG_FILE /* if the hw_addr is written by efuse file, set to NULL */ if (hal_data->efuse_file_status == EFUSE_FILE_LOADED) hw_addr = NULL; #endif if (!hw_addr) { /* try getting hw pg data */ if (Hal_GetPhyEfuseMACAddr(adapter, addr) == _SUCCESS) hw_addr = addr; } #if defined(CONFIG_RTL8822B) && defined(CONFIG_USB_HCI) if (_rtw_memcmp(hw_addr, ft_mac_addr, ETH_ALEN)) hw_addr[0] = 0xff; #endif /* check hw pg data */ if (hw_addr && rtw_check_invalid_mac_address(hw_addr, _TRUE) == _FALSE) { _rtw_memcpy(hal_data->EEPROMMACAddr, hw_addr, ETH_ALEN); goto exit; } bypass_hw_pg: #ifdef CONFIG_EFUSE_CONFIG_FILE /* check wifi mac file */ if (Hal_ReadMACAddrFromFile(adapter, addr) == _SUCCESS) { _rtw_memcpy(hal_data->EEPROMMACAddr, addr, ETH_ALEN); goto exit; } #endif _rtw_memset(hal_data->EEPROMMACAddr, 0, ETH_ALEN); ret = _FAIL; exit: return ret; } #ifdef CONFIG_RF_POWER_TRIM u32 Array_kfreemap[] = { 0x08, 0xe, 0x06, 0xc, 0x04, 0xa, 0x02, 0x8, 0x00, 0x6, 0x03, 0x4, 0x05, 0x2, 0x07, 0x0, 0x09, 0x0, 0x0c, 0x0, }; void rtw_bb_rf_gain_offset(_adapter *padapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); struct registry_priv *registry_par = &padapter->registrypriv; struct kfree_data_t *kfree_data = &pHalData->kfree_data; u8 value = pHalData->EEPROMRFGainOffset; u8 tmp = 0x3e; u32 res, i = 0; u4Byte ArrayLen = sizeof(Array_kfreemap) / sizeof(u32); pu4Byte Array = Array_kfreemap; u4Byte v1 = 0, v2 = 0, GainValue = 0, target = 0; if (registry_par->RegPwrTrimEnable == 2) { RTW_INFO("Registry kfree default force disable.\n"); return; } #if defined(CONFIG_RTL8723B) if (value & BIT4 && (registry_par->RegPwrTrimEnable == 1)) { RTW_INFO("Offset RF Gain.\n"); RTW_INFO("Offset RF Gain. pHalData->EEPROMRFGainVal=0x%x\n", pHalData->EEPROMRFGainVal); if (pHalData->EEPROMRFGainVal != 0xff) { if (pHalData->ant_path == RF_PATH_A) GainValue = (pHalData->EEPROMRFGainVal & 0x0f); else GainValue = (pHalData->EEPROMRFGainVal & 0xf0) >> 4; RTW_INFO("Ant PATH_%d GainValue Offset = 0x%x\n", (pHalData->ant_path == RF_PATH_A) ? (RF_PATH_A) : (RF_PATH_B), GainValue); for (i = 0; i < ArrayLen; i += 2) { /* RTW_INFO("ArrayLen in =%d ,Array 1 =0x%x ,Array2 =0x%x\n",i,Array[i],Array[i]+1); */ v1 = Array[i]; v2 = Array[i + 1]; if (v1 == GainValue) { RTW_INFO("Offset RF Gain. got v1 =0x%x ,v2 =0x%x\n", v1, v2); target = v2; break; } } RTW_INFO("pHalData->EEPROMRFGainVal=0x%x ,Gain offset Target Value=0x%x\n", pHalData->EEPROMRFGainVal, target); res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); RTW_INFO("Offset RF Gain. before reg 0x7f=0x%08x\n", res); phy_set_rf_reg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, BIT18 | BIT17 | BIT16 | BIT15, target); res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); RTW_INFO("Offset RF Gain. After reg 0x7f=0x%08x\n", res); } else RTW_INFO("Offset RF Gain. pHalData->EEPROMRFGainVal=0x%x != 0xff, didn't run Kfree\n", pHalData->EEPROMRFGainVal); } else RTW_INFO("Using the default RF gain.\n"); #elif defined(CONFIG_RTL8188E) if (value & BIT4 && (registry_par->RegPwrTrimEnable == 1)) { RTW_INFO("8188ES Offset RF Gain.\n"); RTW_INFO("8188ES Offset RF Gain. EEPROMRFGainVal=0x%x\n", pHalData->EEPROMRFGainVal); if (pHalData->EEPROMRFGainVal != 0xff) { res = rtw_hal_read_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, 0xffffffff); RTW_INFO("Offset RF Gain. reg 0x55=0x%x\n", res); res &= 0xfff87fff; res |= (pHalData->EEPROMRFGainVal & 0x0f) << 15; RTW_INFO("Offset RF Gain. res=0x%x\n", res); rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); } else { RTW_INFO("Offset RF Gain. EEPROMRFGainVal=0x%x == 0xff, didn't run Kfree\n", pHalData->EEPROMRFGainVal); } } else RTW_INFO("Using the default RF gain.\n"); #else /* TODO: call this when channel switch */ if (kfree_data->flag & KFREE_FLAG_ON) rtw_rf_apply_tx_gain_offset(padapter, 6); /* input ch6 to select BB_GAIN_2G */ #endif } #endif /*CONFIG_RF_POWER_TRIM */ bool kfree_data_is_bb_gain_empty(struct kfree_data_t *data) { #ifdef CONFIG_RF_POWER_TRIM int i, j; for (i = 0; i < BB_GAIN_NUM; i++) for (j = 0; j < RF_PATH_MAX; j++) if (data->bb_gain[i][j] != 0) return 0; #endif return 1; } #ifdef CONFIG_USB_RX_AGGREGATION void rtw_set_usb_agg_by_mode_normal(_adapter *padapter, u8 cur_wireless_mode) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); if (cur_wireless_mode < WIRELESS_11_24N && cur_wireless_mode > 0) { /* ABG mode */ #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER u32 remainder = 0; u8 quotient = 0; remainder = MAX_RECVBUF_SZ % (4 * 1024); quotient = (u8)(MAX_RECVBUF_SZ >> 12); if (quotient > 5) { pHalData->rxagg_usb_size = 0x6; pHalData->rxagg_usb_timeout = 0x10; } else { if (remainder >= 2048) { pHalData->rxagg_usb_size = quotient; pHalData->rxagg_usb_timeout = 0x10; } else { pHalData->rxagg_usb_size = (quotient - 1); pHalData->rxagg_usb_timeout = 0x10; } } #else /* !CONFIG_PREALLOC_RX_SKB_BUFFER */ if (0x6 != pHalData->rxagg_usb_size || 0x10 != pHalData->rxagg_usb_timeout) { pHalData->rxagg_usb_size = 0x6; pHalData->rxagg_usb_timeout = 0x10; rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); } #endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */ } else if (cur_wireless_mode >= WIRELESS_11_24N && cur_wireless_mode <= WIRELESS_MODE_MAX) { /* N AC mode */ #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER u32 remainder = 0; u8 quotient = 0; remainder = MAX_RECVBUF_SZ % (4 * 1024); quotient = (u8)(MAX_RECVBUF_SZ >> 12); if (quotient > 5) { pHalData->rxagg_usb_size = 0x5; pHalData->rxagg_usb_timeout = 0x20; } else { if (remainder >= 2048) { pHalData->rxagg_usb_size = quotient; pHalData->rxagg_usb_timeout = 0x10; } else { pHalData->rxagg_usb_size = (quotient - 1); pHalData->rxagg_usb_timeout = 0x10; } } #else /* !CONFIG_PREALLOC_RX_SKB_BUFFER */ if ((0x5 != pHalData->rxagg_usb_size) || (0x20 != pHalData->rxagg_usb_timeout)) { pHalData->rxagg_usb_size = 0x5; pHalData->rxagg_usb_timeout = 0x20; rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); } #endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */ } else { /* RTW_INFO("%s: Unknow wireless mode(0x%x)\n",__func__,padapter->mlmeextpriv.cur_wireless_mode); */ } } void rtw_set_usb_agg_by_mode_customer(_adapter *padapter, u8 cur_wireless_mode, u8 UsbDmaSize, u8 Legacy_UsbDmaSize) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); if (cur_wireless_mode < WIRELESS_11_24N && cur_wireless_mode > 0) { /* ABG mode */ if (Legacy_UsbDmaSize != pHalData->rxagg_usb_size || 0x10 != pHalData->rxagg_usb_timeout) { pHalData->rxagg_usb_size = Legacy_UsbDmaSize; pHalData->rxagg_usb_timeout = 0x10; rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); } } else if (cur_wireless_mode >= WIRELESS_11_24N && cur_wireless_mode <= WIRELESS_MODE_MAX) { /* N AC mode */ if (UsbDmaSize != pHalData->rxagg_usb_size || 0x20 != pHalData->rxagg_usb_timeout) { pHalData->rxagg_usb_size = UsbDmaSize; pHalData->rxagg_usb_timeout = 0x20; rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); } } else { /* RTW_INFO("%s: Unknown wireless mode(0x%x)\n",__func__,padapter->mlmeextpriv.cur_wireless_mode); */ } } void rtw_set_usb_agg_by_mode(_adapter *padapter, u8 cur_wireless_mode) { #ifdef CONFIG_PLATFORM_NOVATEK_NT72668 rtw_set_usb_agg_by_mode_customer(padapter, cur_wireless_mode, 0x3, 0x3); return; #endif /* CONFIG_PLATFORM_NOVATEK_NT72668 */ rtw_set_usb_agg_by_mode_normal(padapter, cur_wireless_mode); } #endif /* CONFIG_USB_RX_AGGREGATION */ /* To avoid RX affect TX throughput */ void dm_DynamicUsbTxAgg(_adapter *padapter, u8 from_timer) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct registry_priv *registry_par = &padapter->registrypriv; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); u8 cur_wireless_mode = WIRELESS_INVALID; #ifdef CONFIG_USB_RX_AGGREGATION if (!registry_par->dynamic_agg_enable) return; #ifdef RTW_HALMAC if (IS_HARDWARE_TYPE_8822BU(padapter) || IS_HARDWARE_TYPE_8821CU(padapter)) rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, NULL); #else /* !RTW_HALMAC */ if (IS_HARDWARE_TYPE_8821U(padapter)) { /* || IS_HARDWARE_TYPE_8192EU(padapter)) */ /* This AGG_PH_TH only for UsbRxAggMode == USB_RX_AGG_USB */ if ((pHalData->rxagg_mode == RX_AGG_USB) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { if (pdvobjpriv->traffic_stat.cur_tx_tp > 2 && pdvobjpriv->traffic_stat.cur_rx_tp < 30) rtw_write16(padapter , REG_RXDMA_AGG_PG_TH , 0x1010); else if (pdvobjpriv->traffic_stat.last_tx_bytes > 220000 && pdvobjpriv->traffic_stat.cur_rx_tp < 30) rtw_write16(padapter , REG_RXDMA_AGG_PG_TH , 0x1006); else rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, 0x2005); /* dmc agg th 20K */ /* RTW_INFO("TX_TP=%u, RX_TP=%u\n", pdvobjpriv->traffic_stat.cur_tx_tp, pdvobjpriv->traffic_stat.cur_rx_tp); */ } } else if (IS_HARDWARE_TYPE_8812(padapter)) { #ifdef CONFIG_CONCURRENT_MODE u8 i; _adapter *iface; u8 bassocaed = _FALSE; struct mlme_ext_priv *mlmeext; for (i = 0; i < pdvobjpriv->iface_nums; i++) { iface = pdvobjpriv->padapters[i]; mlmeext = &iface->mlmeextpriv; if (rtw_linked_check(iface) == _TRUE) { if (mlmeext->cur_wireless_mode >= cur_wireless_mode) cur_wireless_mode = mlmeext->cur_wireless_mode; bassocaed = _TRUE; } } if (bassocaed) #endif rtw_set_usb_agg_by_mode(padapter, cur_wireless_mode); #ifdef CONFIG_PLATFORM_NOVATEK_NT72668 } else { rtw_set_usb_agg_by_mode(padapter, cur_wireless_mode); #endif /* CONFIG_PLATFORM_NOVATEK_NT72668 */ } #endif /* RTW_HALMAC */ #endif /* CONFIG_USB_RX_AGGREGATION */ } /* bus-agg check for SoftAP mode */ inline u8 rtw_hal_busagg_qsel_check(_adapter *padapter, u8 pre_qsel, u8 next_qsel) { struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); u8 chk_rst = _SUCCESS; if (!MLME_IS_AP(padapter) && !MLME_IS_MESH(padapter)) return chk_rst; /* if((pre_qsel == 0xFF)||(next_qsel== 0xFF)) */ /* return chk_rst; */ if (((pre_qsel == QSLT_HIGH) || ((next_qsel == QSLT_HIGH))) && (pre_qsel != next_qsel)) { /* RTW_INFO("### bus-agg break cause of qsel misatch, pre_qsel=0x%02x,next_qsel=0x%02x ###\n", */ /* pre_qsel,next_qsel); */ chk_rst = _FAIL; } return chk_rst; } /* * Description: * dump_TX_FIFO: This is only used to dump TX_FIFO for debug WoW mode offload * contant. * * Input: * adapter: adapter pointer. * page_num: The max. page number that user want to dump. * page_size: page size of each page. eg. 128 bytes, 256 bytes, 512byte. */ void dump_TX_FIFO(_adapter *padapter, u8 page_num, u16 page_size) { int i; u8 val = 0; u8 base = 0; u32 addr = 0; u32 count = (page_size / 8); if (page_num <= 0) { RTW_INFO("!!%s: incorrect input page_num paramter!\n", __func__); return; } if (page_size < 128 || page_size > 512) { RTW_INFO("!!%s: incorrect input page_size paramter!\n", __func__); return; } RTW_INFO("+%s+\n", __func__); val = rtw_read8(padapter, 0x106); rtw_write8(padapter, 0x106, 0x69); RTW_INFO("0x106: 0x%02x\n", val); base = rtw_read8(padapter, 0x209); RTW_INFO("0x209: 0x%02x\n", base); addr = ((base)*page_size) / 8; for (i = 0 ; i < page_num * count ; i += 2) { rtw_write32(padapter, 0x140, addr + i); printk(" %08x %08x ", rtw_read32(padapter, 0x144), rtw_read32(padapter, 0x148)); rtw_write32(padapter, 0x140, addr + i + 1); printk(" %08x %08x\n", rtw_read32(padapter, 0x144), rtw_read32(padapter, 0x148)); } } #ifdef CONFIG_GPIO_API u8 rtw_hal_get_gpio(_adapter *adapter, u8 gpio_num) { u8 value = 0; u8 direction = 0; u32 gpio_pin_input_val = REG_GPIO_PIN_CTRL; u32 gpio_pin_output_val = REG_GPIO_PIN_CTRL + 1; u32 gpio_pin_output_en = REG_GPIO_PIN_CTRL + 2; u8 gpio_num_to_set = gpio_num; struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); if (rtw_hal_gpio_func_check(adapter, gpio_num) == _FAIL) return value; rtw_ps_deny(adapter, PS_DENY_IOCTL); RTW_INFO("rf_pwrstate=0x%02x\n", pwrpriv->rf_pwrstate); LeaveAllPowerSaveModeDirect(adapter); if (gpio_num > 7) { gpio_pin_input_val = REG_GPIO_PIN_CTRL_2; gpio_pin_output_val = REG_GPIO_PIN_CTRL_2 + 1; gpio_pin_output_en = REG_GPIO_PIN_CTRL_2 + 2; gpio_num_to_set = gpio_num - 8; } /* Read GPIO Direction */ direction = (rtw_read8(adapter, gpio_pin_output_en) & BIT(gpio_num_to_set)) >> gpio_num_to_set; /* According the direction to read register value */ if (direction) value = (rtw_read8(adapter, gpio_pin_output_val) & BIT(gpio_num_to_set)) >> gpio_num_to_set; else value = (rtw_read8(adapter, gpio_pin_input_val) & BIT(gpio_num_to_set)) >> gpio_num_to_set; rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); RTW_INFO("%s direction=%d value=%d\n", __FUNCTION__, direction, value); return value; } int rtw_hal_set_gpio_output_value(_adapter *adapter, u8 gpio_num, bool isHigh) { u8 direction = 0; u8 res = -1; u32 gpio_pin_output_val = REG_GPIO_PIN_CTRL + 1; u32 gpio_pin_output_en = REG_GPIO_PIN_CTRL + 2; u8 gpio_num_to_set = gpio_num; if (rtw_hal_gpio_func_check(adapter, gpio_num) == _FAIL) return -1; rtw_ps_deny(adapter, PS_DENY_IOCTL); LeaveAllPowerSaveModeDirect(adapter); if (gpio_num > 7) { gpio_pin_output_val = REG_GPIO_PIN_CTRL_2 + 1; gpio_pin_output_en = REG_GPIO_PIN_CTRL_2 + 2; gpio_num_to_set = gpio_num - 8; } /* Read GPIO direction */ direction = (rtw_read8(adapter, gpio_pin_output_en) & BIT(gpio_num_to_set)) >> gpio_num_to_set; /* If GPIO is output direction, setting value. */ if (direction) { if (isHigh) rtw_write8(adapter, gpio_pin_output_val, rtw_read8(adapter, gpio_pin_output_val) | BIT(gpio_num_to_set)); else rtw_write8(adapter, gpio_pin_output_val, rtw_read8(adapter, gpio_pin_output_val) & ~BIT(gpio_num_to_set)); RTW_INFO("%s Set gpio %x[%d]=%d\n", __FUNCTION__, REG_GPIO_PIN_CTRL + 1, gpio_num, isHigh); res = 0; } else { RTW_INFO("%s The gpio is input,not be set!\n", __FUNCTION__); res = -1; } rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); return res; } int rtw_hal_config_gpio(_adapter *adapter, u8 gpio_num, bool isOutput) { u32 gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL + 2; u8 gpio_num_to_set = gpio_num; if (rtw_hal_gpio_func_check(adapter, gpio_num) == _FAIL) return -1; RTW_INFO("%s gpio_num =%d direction=%d\n", __FUNCTION__, gpio_num, isOutput); rtw_ps_deny(adapter, PS_DENY_IOCTL); LeaveAllPowerSaveModeDirect(adapter); rtw_hal_gpio_multi_func_reset(adapter, gpio_num); if (gpio_num > 7) { gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL_2 + 2; gpio_num_to_set = gpio_num - 8; } if (isOutput) rtw_write8(adapter, gpio_ctrl_reg_to_set, rtw_read8(adapter, gpio_ctrl_reg_to_set) | BIT(gpio_num_to_set)); else rtw_write8(adapter, gpio_ctrl_reg_to_set, rtw_read8(adapter, gpio_ctrl_reg_to_set) & ~BIT(gpio_num_to_set)); rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); return 0; } int rtw_hal_register_gpio_interrupt(_adapter *adapter, int gpio_num, void(*callback)(u8 level)) { u8 value; u8 direction; PHAL_DATA_TYPE phal = GET_HAL_DATA(adapter); if (IS_HARDWARE_TYPE_8188E(adapter)) { if (gpio_num > 7 || gpio_num < 4) { RTW_PRINT("%s The gpio number does not included 4~7.\n", __FUNCTION__); return -1; } } rtw_ps_deny(adapter, PS_DENY_IOCTL); LeaveAllPowerSaveModeDirect(adapter); /* Read GPIO direction */ direction = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & BIT(gpio_num)) >> gpio_num; if (direction) { RTW_PRINT("%s Can't register output gpio as interrupt.\n", __FUNCTION__); return -1; } /* Config GPIO Mode */ rtw_write8(adapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 3) | BIT(gpio_num)); /* Register GPIO interrupt handler*/ adapter->gpiointpriv.callback[gpio_num] = callback; /* Set GPIO interrupt mode, 0:positive edge, 1:negative edge */ value = rtw_read8(adapter, REG_GPIO_PIN_CTRL) & BIT(gpio_num); adapter->gpiointpriv.interrupt_mode = rtw_read8(adapter, REG_HSIMR + 2) ^ value; rtw_write8(adapter, REG_GPIO_INTM, adapter->gpiointpriv.interrupt_mode); /* Enable GPIO interrupt */ adapter->gpiointpriv.interrupt_enable_mask = rtw_read8(adapter, REG_HSIMR + 2) | BIT(gpio_num); rtw_write8(adapter, REG_HSIMR + 2, adapter->gpiointpriv.interrupt_enable_mask); rtw_hal_update_hisr_hsisr_ind(adapter, 1); rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); return 0; } int rtw_hal_disable_gpio_interrupt(_adapter *adapter, int gpio_num) { u8 value; u8 direction; PHAL_DATA_TYPE phal = GET_HAL_DATA(adapter); if (IS_HARDWARE_TYPE_8188E(adapter)) { if (gpio_num > 7 || gpio_num < 4) { RTW_INFO("%s The gpio number does not included 4~7.\n", __FUNCTION__); return -1; } } rtw_ps_deny(adapter, PS_DENY_IOCTL); LeaveAllPowerSaveModeDirect(adapter); /* Config GPIO Mode */ rtw_write8(adapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(gpio_num)); /* Unregister GPIO interrupt handler*/ adapter->gpiointpriv.callback[gpio_num] = NULL; /* Reset GPIO interrupt mode, 0:positive edge, 1:negative edge */ adapter->gpiointpriv.interrupt_mode = rtw_read8(adapter, REG_GPIO_INTM) & ~BIT(gpio_num); rtw_write8(adapter, REG_GPIO_INTM, 0x00); /* Disable GPIO interrupt */ adapter->gpiointpriv.interrupt_enable_mask = rtw_read8(adapter, REG_HSIMR + 2) & ~BIT(gpio_num); rtw_write8(adapter, REG_HSIMR + 2, adapter->gpiointpriv.interrupt_enable_mask); if (!adapter->gpiointpriv.interrupt_enable_mask) rtw_hal_update_hisr_hsisr_ind(adapter, 0); rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); return 0; } #endif s8 rtw_hal_ch_sw_iqk_info_search(_adapter *padapter, u8 central_chnl, u8 bw_mode) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); u8 i; for (i = 0; i < MAX_IQK_INFO_BACKUP_CHNL_NUM; i++) { if ((pHalData->iqk_reg_backup[i].central_chnl != 0)) { if ((pHalData->iqk_reg_backup[i].central_chnl == central_chnl) && (pHalData->iqk_reg_backup[i].bw_mode == bw_mode)) return i; } } return -1; } void rtw_hal_ch_sw_iqk_info_backup(_adapter *padapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); s8 res; u8 i; /* If it's an existed record, overwrite it */ res = rtw_hal_ch_sw_iqk_info_search(padapter, pHalData->current_channel, pHalData->current_channel_bw); if ((res >= 0) && (res < MAX_IQK_INFO_BACKUP_CHNL_NUM)) { rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_BACKUP, (u8 *)&(pHalData->iqk_reg_backup[res])); return; } /* Search for the empty record to use */ for (i = 0; i < MAX_IQK_INFO_BACKUP_CHNL_NUM; i++) { if (pHalData->iqk_reg_backup[i].central_chnl == 0) { rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_BACKUP, (u8 *)&(pHalData->iqk_reg_backup[i])); return; } } /* Else, overwrite the oldest record */ for (i = 1; i < MAX_IQK_INFO_BACKUP_CHNL_NUM; i++) _rtw_memcpy(&(pHalData->iqk_reg_backup[i - 1]), &(pHalData->iqk_reg_backup[i]), sizeof(struct hal_iqk_reg_backup)); rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_BACKUP, (u8 *)&(pHalData->iqk_reg_backup[MAX_IQK_INFO_BACKUP_CHNL_NUM - 1])); } void rtw_hal_ch_sw_iqk_info_restore(_adapter *padapter, u8 ch_sw_use_case) { rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_RESTORE, &ch_sw_use_case); } void rtw_dump_mac_rx_counters(_adapter *padapter, struct dbg_rx_counter *rx_counter) { u32 mac_cck_ok = 0, mac_ofdm_ok = 0, mac_ht_ok = 0, mac_vht_ok = 0; u32 mac_cck_err = 0, mac_ofdm_err = 0, mac_ht_err = 0, mac_vht_err = 0; u32 mac_cck_fa = 0, mac_ofdm_fa = 0, mac_ht_fa = 0; u32 DropPacket = 0; if (!rx_counter) { rtw_warn_on(1); return; } if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x0);/*clear bit-26*/ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x3); mac_cck_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x0); mac_ofdm_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x6); mac_ht_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ mac_vht_ok = 0; if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x0); phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x1); mac_vht_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0]*/ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x0);/*clear bit-26*/ } phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x4); mac_cck_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x1); mac_ofdm_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x7); mac_ht_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ mac_vht_err = 0; if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x1); phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x1); mac_vht_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0]*/ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x0);/*clear bit-26*/ } phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x5); mac_cck_fa = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x2); mac_ofdm_fa = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x9); mac_ht_fa = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ /* Mac_DropPacket */ rtw_write32(padapter, REG_RXERR_RPT, (rtw_read32(padapter, REG_RXERR_RPT) & 0x0FFFFFFF) | Mac_DropPacket); DropPacket = rtw_read32(padapter, REG_RXERR_RPT) & 0x0000FFFF; rx_counter->rx_pkt_ok = mac_cck_ok + mac_ofdm_ok + mac_ht_ok + mac_vht_ok; rx_counter->rx_pkt_crc_error = mac_cck_err + mac_ofdm_err + mac_ht_err + mac_vht_err; rx_counter->rx_cck_fa = mac_cck_fa; rx_counter->rx_ofdm_fa = mac_ofdm_fa; rx_counter->rx_ht_fa = mac_ht_fa; rx_counter->rx_pkt_drop = DropPacket; } void rtw_reset_mac_rx_counters(_adapter *padapter) { /* If no packet rx, MaxRx clock be gating ,BIT_DISGCLK bit19 set 1 for fix*/ if (IS_HARDWARE_TYPE_8703B(padapter) || IS_HARDWARE_TYPE_8723D(padapter) || IS_HARDWARE_TYPE_8188F(padapter)) phy_set_mac_reg(padapter, REG_RCR, BIT19, 0x1); /* reset mac counter */ phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT27, 0x1); phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT27, 0x0); } void rtw_dump_phy_rx_counters(_adapter *padapter, struct dbg_rx_counter *rx_counter) { u32 cckok = 0, cckcrc = 0, ofdmok = 0, ofdmcrc = 0, htok = 0, htcrc = 0, OFDM_FA = 0, CCK_FA = 0, vht_ok = 0, vht_err = 0; if (!rx_counter) { rtw_warn_on(1); return; } if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { cckok = phy_query_bb_reg(padapter, 0xF04, 0x3FFF); /* [13:0] */ ofdmok = phy_query_bb_reg(padapter, 0xF14, 0x3FFF); /* [13:0] */ htok = phy_query_bb_reg(padapter, 0xF10, 0x3FFF); /* [13:0] */ vht_ok = phy_query_bb_reg(padapter, 0xF0C, 0x3FFF); /* [13:0] */ cckcrc = phy_query_bb_reg(padapter, 0xF04, 0x3FFF0000); /* [29:16] */ ofdmcrc = phy_query_bb_reg(padapter, 0xF14, 0x3FFF0000); /* [29:16] */ htcrc = phy_query_bb_reg(padapter, 0xF10, 0x3FFF0000); /* [29:16] */ vht_err = phy_query_bb_reg(padapter, 0xF0C, 0x3FFF0000); /* [29:16] */ CCK_FA = phy_query_bb_reg(padapter, 0xA5C, bMaskLWord); OFDM_FA = phy_query_bb_reg(padapter, 0xF48, bMaskLWord); } else { cckok = phy_query_bb_reg(padapter, 0xF88, bMaskDWord); ofdmok = phy_query_bb_reg(padapter, 0xF94, bMaskLWord); htok = phy_query_bb_reg(padapter, 0xF90, bMaskLWord); vht_ok = 0; cckcrc = phy_query_bb_reg(padapter, 0xF84, bMaskDWord); ofdmcrc = phy_query_bb_reg(padapter, 0xF94, bMaskHWord); htcrc = phy_query_bb_reg(padapter, 0xF90, bMaskHWord); vht_err = 0; OFDM_FA = phy_query_bb_reg(padapter, 0xCF0, bMaskLWord) + phy_query_bb_reg(padapter, 0xCF2, bMaskLWord) + phy_query_bb_reg(padapter, 0xDA2, bMaskLWord) + phy_query_bb_reg(padapter, 0xDA4, bMaskLWord) + phy_query_bb_reg(padapter, 0xDA6, bMaskLWord) + phy_query_bb_reg(padapter, 0xDA8, bMaskLWord); CCK_FA = (rtw_read8(padapter, 0xA5B) << 8) | (rtw_read8(padapter, 0xA5C)); } rx_counter->rx_pkt_ok = cckok + ofdmok + htok + vht_ok; rx_counter->rx_pkt_crc_error = cckcrc + ofdmcrc + htcrc + vht_err; rx_counter->rx_ofdm_fa = OFDM_FA; rx_counter->rx_cck_fa = CCK_FA; } void rtw_reset_phy_trx_ok_counters(_adapter *padapter) { if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { phy_set_bb_reg(padapter, 0xB58, BIT0, 0x1); phy_set_bb_reg(padapter, 0xB58, BIT0, 0x0); } } void rtw_reset_phy_rx_counters(_adapter *padapter) { /* reset phy counter */ if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { rtw_reset_phy_trx_ok_counters(padapter); phy_set_bb_reg(padapter, 0x9A4, BIT17, 0x1);/* reset OFDA FA counter */ phy_set_bb_reg(padapter, 0x9A4, BIT17, 0x0); phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x0);/* reset CCK FA counter */ phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x1); } else { phy_set_bb_reg(padapter, 0xF14, BIT16, 0x1); rtw_msleep_os(10); phy_set_bb_reg(padapter, 0xF14, BIT16, 0x0); phy_set_bb_reg(padapter, 0xD00, BIT27, 0x1);/* reset OFDA FA counter */ phy_set_bb_reg(padapter, 0xC0C, BIT31, 0x1);/* reset OFDA FA counter */ phy_set_bb_reg(padapter, 0xD00, BIT27, 0x0); phy_set_bb_reg(padapter, 0xC0C, BIT31, 0x0); phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x0);/* reset CCK FA counter */ phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x1); } } #ifdef DBG_RX_COUNTER_DUMP void rtw_dump_drv_rx_counters(_adapter *padapter, struct dbg_rx_counter *rx_counter) { struct recv_priv *precvpriv = &padapter->recvpriv; if (!rx_counter) { rtw_warn_on(1); return; } rx_counter->rx_pkt_ok = padapter->drv_rx_cnt_ok; rx_counter->rx_pkt_crc_error = padapter->drv_rx_cnt_crcerror; rx_counter->rx_pkt_drop = precvpriv->rx_drop - padapter->drv_rx_cnt_drop; } void rtw_reset_drv_rx_counters(_adapter *padapter) { struct recv_priv *precvpriv = &padapter->recvpriv; padapter->drv_rx_cnt_ok = 0; padapter->drv_rx_cnt_crcerror = 0; padapter->drv_rx_cnt_drop = precvpriv->rx_drop; } void rtw_dump_phy_rxcnts_preprocess(_adapter *padapter, u8 rx_cnt_mode) { u8 initialgain; HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); if ((!(padapter->dump_rx_cnt_mode & DUMP_PHY_RX_COUNTER)) && (rx_cnt_mode & DUMP_PHY_RX_COUNTER)) { rtw_hal_get_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, NULL); RTW_INFO("%s CurIGValue:0x%02x\n", __FUNCTION__, initialgain); rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE); /*disable dynamic functions, such as high power, DIG*/ rtw_phydm_ability_backup(padapter); rtw_phydm_func_clr(padapter, (ODM_BB_DIG | ODM_BB_FA_CNT)); } else if ((padapter->dump_rx_cnt_mode & DUMP_PHY_RX_COUNTER) && (!(rx_cnt_mode & DUMP_PHY_RX_COUNTER))) { /* turn on phy-dynamic functions */ rtw_phydm_ability_restore(padapter); initialgain = 0xff; /* restore RX GAIN */ rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE); } } void rtw_dump_rx_counters(_adapter *padapter) { struct dbg_rx_counter rx_counter; if (padapter->dump_rx_cnt_mode & DUMP_DRV_RX_COUNTER) { _rtw_memset(&rx_counter, 0, sizeof(struct dbg_rx_counter)); rtw_dump_drv_rx_counters(padapter, &rx_counter); RTW_INFO("Drv Received packet OK:%d CRC error:%d Drop Packets: %d\n", rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, rx_counter.rx_pkt_drop); rtw_reset_drv_rx_counters(padapter); } if (padapter->dump_rx_cnt_mode & DUMP_MAC_RX_COUNTER) { _rtw_memset(&rx_counter, 0, sizeof(struct dbg_rx_counter)); rtw_dump_mac_rx_counters(padapter, &rx_counter); RTW_INFO("Mac Received packet OK:%d CRC error:%d FA Counter: %d Drop Packets: %d\n", rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, rx_counter.rx_cck_fa + rx_counter.rx_ofdm_fa + rx_counter.rx_ht_fa, rx_counter.rx_pkt_drop); rtw_reset_mac_rx_counters(padapter); } if (padapter->dump_rx_cnt_mode & DUMP_PHY_RX_COUNTER) { _rtw_memset(&rx_counter, 0, sizeof(struct dbg_rx_counter)); rtw_dump_phy_rx_counters(padapter, &rx_counter); /* RTW_INFO("%s: OFDM_FA =%d\n", __FUNCTION__, rx_counter.rx_ofdm_fa); */ /* RTW_INFO("%s: CCK_FA =%d\n", __FUNCTION__, rx_counter.rx_cck_fa); */ RTW_INFO("Phy Received packet OK:%d CRC error:%d FA Counter: %d\n", rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, rx_counter.rx_ofdm_fa + rx_counter.rx_cck_fa); rtw_reset_phy_rx_counters(padapter); } } #endif u8 rtw_get_current_tx_sgi(_adapter *padapter, struct sta_info *psta) { u8 curr_tx_sgi = 0; struct ra_sta_info *ra_info; if (!psta) return curr_tx_sgi; if (padapter->fix_rate == 0xff) { ra_info = &psta->cmn.ra_info; curr_tx_sgi = ((ra_info->curr_tx_rate) & 0x80) >> 7; } else { curr_tx_sgi = ((padapter->fix_rate) & 0x80) >> 7; } return curr_tx_sgi; } u8 rtw_get_current_tx_rate(_adapter *padapter, struct sta_info *psta) { u8 rate_id = 0; struct ra_sta_info *ra_info; if (!psta) return rate_id; if (padapter->fix_rate == 0xff) { ra_info = &psta->cmn.ra_info; rate_id = ra_info->curr_tx_rate & 0x7f; } else { rate_id = padapter->fix_rate & 0x7f; } return rate_id; } void update_IOT_info(_adapter *padapter) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); switch (pmlmeinfo->assoc_AP_vendor) { case HT_IOT_PEER_MARVELL: pmlmeinfo->turboMode_cts2self = 1; pmlmeinfo->turboMode_rtsen = 0; break; case HT_IOT_PEER_RALINK: pmlmeinfo->turboMode_cts2self = 0; pmlmeinfo->turboMode_rtsen = 1; break; case HT_IOT_PEER_REALTEK: /* rtw_write16(padapter, 0x4cc, 0xffff); */ /* rtw_write16(padapter, 0x546, 0x01c0); */ break; default: pmlmeinfo->turboMode_cts2self = 0; pmlmeinfo->turboMode_rtsen = 1; break; } } /* TODO: merge with phydm, see odm_SetCrystalCap() */ void hal_set_crystal_cap(_adapter *adapter, u8 crystal_cap) { crystal_cap = crystal_cap & 0x3F; switch (rtw_get_chip_type(adapter)) { #if defined(CONFIG_RTL8188E) || defined(CONFIG_RTL8188F) case RTL8188E: case RTL8188F: /* write 0x24[16:11] = 0x24[22:17] = CrystalCap */ phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x007FF800, (crystal_cap | (crystal_cap << 6))); break; #endif #if defined(CONFIG_RTL8812A) case RTL8812: /* write 0x2C[30:25] = 0x2C[24:19] = CrystalCap */ phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x7FF80000, (crystal_cap | (crystal_cap << 6))); break; #endif #if defined(CONFIG_RTL8723B) || defined(CONFIG_RTL8703B) || \ defined(CONFIG_RTL8723D) || defined(CONFIG_RTL8821A) || \ defined(CONFIG_RTL8192E) case RTL8723B: case RTL8703B: case RTL8723D: case RTL8821: case RTL8192E: /* write 0x2C[23:18] = 0x2C[17:12] = CrystalCap */ phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x00FFF000, (crystal_cap | (crystal_cap << 6))); break; #endif #if defined(CONFIG_RTL8814A) case RTL8814A: /* write 0x2C[26:21] = 0x2C[20:15] = CrystalCap*/ phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x07FF8000, (crystal_cap | (crystal_cap << 6))); break; #endif #if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) case RTL8822B: case RTL8821C: /* write 0x28[6:1] = 0x24[30:25] = CrystalCap */ crystal_cap = crystal_cap & 0x3F; phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x7E000000, crystal_cap); phy_set_bb_reg(adapter, REG_AFE_PLL_CTRL, 0x7E, crystal_cap); break; #endif default: rtw_warn_on(1); } } int hal_spec_init(_adapter *adapter) { u8 interface_type = 0; int ret = _SUCCESS; interface_type = rtw_get_intf_type(adapter); switch (rtw_get_chip_type(adapter)) { #ifdef CONFIG_RTL8723B case RTL8723B: init_hal_spec_8723b(adapter); break; #endif #ifdef CONFIG_RTL8703B case RTL8703B: init_hal_spec_8703b(adapter); break; #endif #ifdef CONFIG_RTL8723D case RTL8723D: init_hal_spec_8723d(adapter); break; #endif #ifdef CONFIG_RTL8188E case RTL8188E: init_hal_spec_8188e(adapter); break; #endif #ifdef CONFIG_RTL8188F case RTL8188F: init_hal_spec_8188f(adapter); break; #endif #ifdef CONFIG_RTL8812A case RTL8812: init_hal_spec_8812a(adapter); break; #endif #ifdef CONFIG_RTL8821A case RTL8821: init_hal_spec_8821a(adapter); break; #endif #ifdef CONFIG_RTL8192E case RTL8192E: init_hal_spec_8192e(adapter); break; #endif #ifdef CONFIG_RTL8814A case RTL8814A: init_hal_spec_8814a(adapter); break; #endif #ifdef CONFIG_RTL8822B case RTL8822B: rtl8822b_init_hal_spec(adapter); break; #endif #ifdef CONFIG_RTL8821C case RTL8821C: init_hal_spec_rtl8821c(adapter); break; #endif default: RTW_ERR("%s: unknown chip_type:%u\n" , __func__, rtw_get_chip_type(adapter)); ret = _FAIL; break; } return ret; } static const char *const _band_cap_str[] = { /* BIT0 */"2G", /* BIT1 */"5G", }; static const char *const _bw_cap_str[] = { /* BIT0 */"5M", /* BIT1 */"10M", /* BIT2 */"20M", /* BIT3 */"40M", /* BIT4 */"80M", /* BIT5 */"160M", /* BIT6 */"80_80M", }; static const char *const _proto_cap_str[] = { /* BIT0 */"b", /* BIT1 */"g", /* BIT2 */"n", /* BIT3 */"ac", }; static const char *const _wl_func_str[] = { /* BIT0 */"P2P", /* BIT1 */"MIRACAST", /* BIT2 */"TDLS", /* BIT3 */"FTM", }; void dump_hal_spec(void *sel, _adapter *adapter) { struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); int i; RTW_PRINT_SEL(sel, "macid_num:%u\n", hal_spec->macid_num); RTW_PRINT_SEL(sel, "sec_cap:0x%02x\n", hal_spec->sec_cap); RTW_PRINT_SEL(sel, "sec_cam_ent_num:%u\n", hal_spec->sec_cam_ent_num); RTW_PRINT_SEL(sel, "rfpath_num_2g:%u\n", hal_spec->rfpath_num_2g); RTW_PRINT_SEL(sel, "rfpath_num_5g:%u\n", hal_spec->rfpath_num_5g); RTW_PRINT_SEL(sel, "max_tx_cnt:%u\n", hal_spec->max_tx_cnt); RTW_PRINT_SEL(sel, "tx_nss_num:%u\n", hal_spec->tx_nss_num); RTW_PRINT_SEL(sel, "rx_nss_num:%u\n", hal_spec->rx_nss_num); RTW_PRINT_SEL(sel, "band_cap:"); for (i = 0; i < BAND_CAP_BIT_NUM; i++) { if (((hal_spec->band_cap) >> i) & BIT0 && _band_cap_str[i]) _RTW_PRINT_SEL(sel, "%s ", _band_cap_str[i]); } _RTW_PRINT_SEL(sel, "\n"); RTW_PRINT_SEL(sel, "bw_cap:"); for (i = 0; i < BW_CAP_BIT_NUM; i++) { if (((hal_spec->bw_cap) >> i) & BIT0 && _bw_cap_str[i]) _RTW_PRINT_SEL(sel, "%s ", _bw_cap_str[i]); } _RTW_PRINT_SEL(sel, "\n"); RTW_PRINT_SEL(sel, "proto_cap:"); for (i = 0; i < PROTO_CAP_BIT_NUM; i++) { if (((hal_spec->proto_cap) >> i) & BIT0 && _proto_cap_str[i]) _RTW_PRINT_SEL(sel, "%s ", _proto_cap_str[i]); } _RTW_PRINT_SEL(sel, "\n"); RTW_PRINT_SEL(sel, "wl_func:"); for (i = 0; i < WL_FUNC_BIT_NUM; i++) { if (((hal_spec->wl_func) >> i) & BIT0 && _wl_func_str[i]) _RTW_PRINT_SEL(sel, "%s ", _wl_func_str[i]); } _RTW_PRINT_SEL(sel, "\n"); RTW_PRINT_SEL(sel, "pg_txpwr_saddr:0x%X\n", hal_spec->pg_txpwr_saddr); } inline bool hal_chk_band_cap(_adapter *adapter, u8 cap) { return GET_HAL_SPEC(adapter)->band_cap & cap; } inline bool hal_chk_bw_cap(_adapter *adapter, u8 cap) { return GET_HAL_SPEC(adapter)->bw_cap & cap; } inline bool hal_chk_proto_cap(_adapter *adapter, u8 cap) { return GET_HAL_SPEC(adapter)->proto_cap & cap; } inline bool hal_chk_wl_func(_adapter *adapter, u8 func) { return GET_HAL_SPEC(adapter)->wl_func & func; } inline bool hal_is_band_support(_adapter *adapter, u8 band) { return GET_HAL_SPEC(adapter)->band_cap & band_to_band_cap(band); } inline bool hal_is_bw_support(_adapter *adapter, u8 bw) { return GET_HAL_SPEC(adapter)->bw_cap & ch_width_to_bw_cap(bw); } inline bool hal_is_wireless_mode_support(_adapter *adapter, u8 mode) { u8 proto_cap = GET_HAL_SPEC(adapter)->proto_cap; if (mode == WIRELESS_11B) if ((proto_cap & PROTO_CAP_11B) && hal_chk_band_cap(adapter, BAND_CAP_2G)) return 1; if (mode == WIRELESS_11G) if ((proto_cap & PROTO_CAP_11G) && hal_chk_band_cap(adapter, BAND_CAP_2G)) return 1; if (mode == WIRELESS_11A) if ((proto_cap & PROTO_CAP_11G) && hal_chk_band_cap(adapter, BAND_CAP_5G)) return 1; if (mode == WIRELESS_11_24N) if ((proto_cap & PROTO_CAP_11N) && hal_chk_band_cap(adapter, BAND_CAP_2G)) return 1; if (mode == WIRELESS_11_5N) if ((proto_cap & PROTO_CAP_11N) && hal_chk_band_cap(adapter, BAND_CAP_5G)) return 1; if (mode == WIRELESS_11AC) if ((proto_cap & PROTO_CAP_11AC) && hal_chk_band_cap(adapter, BAND_CAP_5G)) return 1; return 0; } /* * hal_largest_bw - starting from in_bw, get largest bw supported by HAL * @adapter: * @in_bw: starting bw, value of enum channel_width * * Returns: value of enum channel_width */ u8 hal_largest_bw(_adapter *adapter, u8 in_bw) { for (; in_bw > CHANNEL_WIDTH_20; in_bw--) { if (hal_is_bw_support(adapter, in_bw)) break; } if (!hal_is_bw_support(adapter, in_bw)) rtw_warn_on(1); return in_bw; } void rtw_hal_correct_tsf(_adapter *padapter, u8 hw_port, u64 tsf) { if (hw_port == HW_PORT0) { /*disable related TSF function*/ rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL) & (~EN_BCN_FUNCTION)); rtw_write32(padapter, REG_TSFTR, tsf); rtw_write32(padapter, REG_TSFTR + 4, tsf >> 32); /*enable related TSF function*/ rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL) | EN_BCN_FUNCTION); } else if (hw_port == HW_PORT1) { /*disable related TSF function*/ rtw_write8(padapter, REG_BCN_CTRL_1, rtw_read8(padapter, REG_BCN_CTRL_1) & (~EN_BCN_FUNCTION)); rtw_write32(padapter, REG_TSFTR1, tsf); rtw_write32(padapter, REG_TSFTR1 + 4, tsf >> 32); /*enable related TSF function*/ rtw_write8(padapter, REG_BCN_CTRL_1, rtw_read8(padapter, REG_BCN_CTRL_1) | EN_BCN_FUNCTION); } else RTW_INFO("%s-[WARN] "ADPT_FMT" invalid hw_port:%d\n", __func__, ADPT_ARG(padapter), hw_port); } void ResumeTxBeacon(_adapter *padapter) { #ifdef CONFIG_MI_WITH_MBSSID_CAM #else rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, rtw_read8(padapter, REG_FWHW_TXQ_CTRL + 2) | BIT(6)); #ifdef RTW_HALMAC /* Add this for driver using HALMAC because driver doesn't have setup time init by self */ /* TBTT setup time */ rtw_write8(padapter, REG_TBTT_PROHIBIT, TBTT_PROHIBIT_SETUP_TIME); #endif /* TBTT hold time: 0x540[19:8] */ rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, TBTT_PROHIBIT_HOLD_TIME & 0xFF); rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, (rtw_read8(padapter, REG_TBTT_PROHIBIT + 2) & 0xF0) | (TBTT_PROHIBIT_HOLD_TIME >> 8)); #endif } void StopTxBeacon(_adapter *padapter) { #ifdef CONFIG_MI_WITH_MBSSID_CAM #else rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, rtw_read8(padapter, REG_FWHW_TXQ_CTRL + 2) & (~BIT6)); /* TBTT hold time: 0x540[19:8] */ rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, TBTT_PROHIBIT_HOLD_TIME_STOP_BCN & 0xFF); rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, (rtw_read8(padapter, REG_TBTT_PROHIBIT + 2) & 0xF0) | (TBTT_PROHIBIT_HOLD_TIME_STOP_BCN >> 8)); #endif } #ifdef CONFIG_MI_WITH_MBSSID_CAM /*HW port0 - MBSS*/ void hw_var_set_opmode_mbid(_adapter *Adapter, u8 mode) { RTW_INFO("%s()-"ADPT_FMT" mode = %d\n", __func__, ADPT_ARG(Adapter), mode); rtw_hal_rcr_set_chk_bssid(Adapter, MLME_ACTION_NONE); /* disable Port0 TSF update*/ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | DIS_TSF_UDT); /* set net_type */ Set_MSR(Adapter, mode); if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { if (!rtw_mi_get_ap_num(Adapter) && !rtw_mi_get_mesh_num(Adapter)) StopTxBeacon(Adapter); rtw_write8(Adapter, REG_BCN_CTRL, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_ATIM);/*disable atim wnd*/ } else if (mode == _HW_STATE_ADHOC_) { ResumeTxBeacon(Adapter); rtw_write8(Adapter, REG_BCN_CTRL, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB); } else if (mode == _HW_STATE_AP_) { ResumeTxBeacon(Adapter); rtw_write8(Adapter, REG_BCN_CTRL, DIS_TSF_UDT | DIS_BCNQ_SUB); /*enable to rx data frame*/ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); /*Beacon Control related register for first time*/ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); /* 2ms */ /*rtw_write8(Adapter, REG_BCN_MAX_ERR, 0xFF);*/ rtw_write8(Adapter, REG_ATIMWND, 0x0c); /* 12ms */ rtw_write16(Adapter, REG_BCNTCFG, 0x00); rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */ /*reset TSF*/ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); /*enable BCN0 Function for if1*/ /*don't enable update TSF0 for if1 (due to TSF update when beacon,probe rsp are received)*/ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT | EN_BCN_FUNCTION | EN_TXBCN_RPT | DIS_BCNQ_SUB)); #ifdef CONFIG_BCN_XMIT_PROTECT rtw_write8(Adapter, REG_CCK_CHECK, rtw_read8(Adapter, REG_CCK_CHECK) | BIT_EN_BCN_PKT_REL); #endif if (IS_HARDWARE_TYPE_8821(Adapter) || IS_HARDWARE_TYPE_8192E(Adapter))/* select BCN on port 0 for DualBeacon*/ rtw_write8(Adapter, REG_CCK_CHECK, rtw_read8(Adapter, REG_CCK_CHECK) & (~BIT_BCN_PORT_SEL)); } } #endif #ifdef CONFIG_ANTENNA_DIVERSITY u8 rtw_hal_antdiv_before_linked(_adapter *padapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); u8 cur_ant, change_ant; if (!pHalData->AntDivCfg) return _FALSE; if (pHalData->sw_antdiv_bl_state == 0) { pHalData->sw_antdiv_bl_state = 1; rtw_hal_get_odm_var(padapter, HAL_ODM_ANTDIV_SELECT, &cur_ant, NULL); change_ant = (cur_ant == MAIN_ANT) ? AUX_ANT : MAIN_ANT; return rtw_antenna_select_cmd(padapter, change_ant, _FALSE); } pHalData->sw_antdiv_bl_state = 0; return _FALSE; } void rtw_hal_antdiv_rssi_compared(_adapter *padapter, WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); if (pHalData->AntDivCfg) { /*RTW_INFO("update_network=> org-RSSI(%d), new-RSSI(%d)\n", dst->Rssi, src->Rssi);*/ /*select optimum_antenna for before linked =>For antenna diversity*/ if (dst->Rssi >= src->Rssi) {/*keep org parameter*/ src->Rssi = dst->Rssi; src->PhyInfo.Optimum_antenna = dst->PhyInfo.Optimum_antenna; } } } #endif #ifdef CONFIG_PHY_CAPABILITY_QUERY void rtw_dump_phy_cap_by_phydmapi(void *sel, _adapter *adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); struct phy_spec_t *phy_spec = &pHalData->phy_spec; RTW_PRINT_SEL(sel, "[PHY SPEC] TRx Capability : 0x%08x\n", phy_spec->trx_cap); RTW_PRINT_SEL(sel, "[PHY SPEC] Tx Stream Num Index : %d\n", (phy_spec->trx_cap >> 24) & 0xFF); /*Tx Stream Num Index [31:24]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] Rx Stream Num Index : %d\n", (phy_spec->trx_cap >> 16) & 0xFF); /*Rx Stream Num Index [23:16]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] Tx Path Num Index : %d\n", (phy_spec->trx_cap >> 8) & 0xFF);/*Tx Path Num Index [15:8]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] Rx Path Num Index : %d\n\n", (phy_spec->trx_cap & 0xFF));/*Rx Path Num Index [7:0]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] STBC Capability : 0x%08x\n", phy_spec->stbc_cap); RTW_PRINT_SEL(sel, "[PHY SPEC] VHT STBC Tx : %s\n", ((phy_spec->stbc_cap >> 24) & 0xFF) ? "Supported" : "N/A"); /*VHT STBC Tx [31:24]*/ /*VHT STBC Rx [23:16] 0 = not support 1 = support for 1 spatial stream 2 = support for 1 or 2 spatial streams 3 = support for 1 or 2 or 3 spatial streams 4 = support for 1 or 2 or 3 or 4 spatial streams*/ RTW_PRINT_SEL(sel, "[PHY SPEC] VHT STBC Rx :%d\n", ((phy_spec->stbc_cap >> 16) & 0xFF)); RTW_PRINT_SEL(sel, "[PHY SPEC] HT STBC Tx : %s\n", ((phy_spec->stbc_cap >> 8) & 0xFF) ? "Supported" : "N/A"); /*HT STBC Tx [15:8]*/ /*HT STBC Rx [7:0] 0 = not support 1 = support for 1 spatial stream 2 = support for 1 or 2 spatial streams 3 = support for 1 or 2 or 3 spatial streams*/ RTW_PRINT_SEL(sel, "[PHY SPEC] HT STBC Rx : %d\n\n", (phy_spec->stbc_cap & 0xFF)); RTW_PRINT_SEL(sel, "[PHY SPEC] LDPC Capability : 0x%08x\n", phy_spec->ldpc_cap); RTW_PRINT_SEL(sel, "[PHY SPEC] VHT LDPC Tx : %s\n", ((phy_spec->ldpc_cap >> 24) & 0xFF) ? "Supported" : "N/A"); /*VHT LDPC Tx [31:24]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] VHT LDPC Rx : %s\n", ((phy_spec->ldpc_cap >> 16) & 0xFF) ? "Supported" : "N/A"); /*VHT LDPC Rx [23:16]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] HT LDPC Tx : %s\n", ((phy_spec->ldpc_cap >> 8) & 0xFF) ? "Supported" : "N/A"); /*HT LDPC Tx [15:8]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] HT LDPC Rx : %s\n\n", (phy_spec->ldpc_cap & 0xFF) ? "Supported" : "N/A"); /*HT LDPC Rx [7:0]*/ #ifdef CONFIG_BEAMFORMING RTW_PRINT_SEL(sel, "[PHY SPEC] TxBF Capability : 0x%08x\n", phy_spec->txbf_cap); RTW_PRINT_SEL(sel, "[PHY SPEC] VHT MU Bfer : %s\n", ((phy_spec->txbf_cap >> 28) & 0xF) ? "Supported" : "N/A"); /*VHT MU Bfer [31:28]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] VHT MU Bfee : %s\n", ((phy_spec->txbf_cap >> 24) & 0xF) ? "Supported" : "N/A"); /*VHT MU Bfee [27:24]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] VHT SU Bfer : %s\n", ((phy_spec->txbf_cap >> 20) & 0xF) ? "Supported" : "N/A"); /*VHT SU Bfer [23:20]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] VHT SU Bfee : %s\n", ((phy_spec->txbf_cap >> 16) & 0xF) ? "Supported" : "N/A"); /*VHT SU Bfee [19:16]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] HT Bfer : %s\n", ((phy_spec->txbf_cap >> 4) & 0xF) ? "Supported" : "N/A"); /*HT Bfer [7:4]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] HT Bfee : %s\n\n", (phy_spec->txbf_cap & 0xF) ? "Supported" : "N/A"); /*HT Bfee [3:0]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] TxBF parameter : 0x%08x\n", phy_spec->txbf_param); RTW_PRINT_SEL(sel, "[PHY SPEC] VHT Sounding Dim : %d\n", (phy_spec->txbf_param >> 24) & 0xFF); /*VHT Sounding Dim [31:24]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] VHT Steering Ant : %d\n", (phy_spec->txbf_param >> 16) & 0xFF); /*VHT Steering Ant [23:16]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] HT Sounding Dim : %d\n", (phy_spec->txbf_param >> 8) & 0xFF); /*HT Sounding Dim [15:8]*/ RTW_PRINT_SEL(sel, "[PHY SPEC] HT Steering Ant : %d\n", phy_spec->txbf_param & 0xFF); /*HT Steering Ant [7:0]*/ #endif } #else void rtw_dump_phy_cap_by_hal(void *sel, _adapter *adapter) { u8 phy_cap = _FALSE; /* STBC */ rtw_hal_get_def_var(adapter, HAL_DEF_TX_STBC, (u8 *)&phy_cap); RTW_PRINT_SEL(sel, "[HAL] STBC Tx : %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); phy_cap = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_RX_STBC, (u8 *)&phy_cap); RTW_PRINT_SEL(sel, "[HAL] STBC Rx : %s\n\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); /* LDPC support */ phy_cap = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_TX_LDPC, (u8 *)&phy_cap); RTW_PRINT_SEL(sel, "[HAL] LDPC Tx : %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); phy_cap = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_RX_LDPC, (u8 *)&phy_cap); RTW_PRINT_SEL(sel, "[HAL] LDPC Rx : %s\n\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); #ifdef CONFIG_BEAMFORMING phy_cap = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&phy_cap); RTW_PRINT_SEL(sel, "[HAL] Beamformer: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); phy_cap = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&phy_cap); RTW_PRINT_SEL(sel, "[HAL] Beamformee: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); phy_cap = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_VHT_MU_BEAMFORMER, &phy_cap); RTW_PRINT_SEL(sel, "[HAL] VHT MU Beamformer: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); phy_cap = _FALSE; rtw_hal_get_def_var(adapter, HAL_DEF_VHT_MU_BEAMFORMEE, &phy_cap); RTW_PRINT_SEL(sel, "[HAL] VHT MU Beamformee: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); #endif } #endif void rtw_dump_phy_cap(void *sel, _adapter *adapter) { RTW_PRINT_SEL(sel, "\n ======== PHY Capability ========\n"); #ifdef CONFIG_PHY_CAPABILITY_QUERY rtw_dump_phy_cap_by_phydmapi(sel, adapter); #else rtw_dump_phy_cap_by_hal(sel, adapter); #endif } inline s16 translate_dbm_to_percentage(s16 signal) { if ((signal <= -100) || (signal >= 20)) return 0; else if (signal >= 0) return 100; else return 100 + signal; } #ifdef CONFIG_SWTIMER_BASED_TXBCN #ifdef CONFIG_BCN_RECOVERY #define REG_CPU_MGQ_INFO 0x041C #define BIT_BCN_POLL BIT(28) u8 rtw_ap_bcn_recovery(_adapter *padapter) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); if (hal_data->issue_bcn_fail >= 2) { RTW_ERR("%s ISSUE BCN Fail\n", __func__); rtw_write8(padapter, REG_CPU_MGQ_INFO + 3, 0x10); hal_data->issue_bcn_fail = 0; } return _SUCCESS; } #endif /*CONFIG_BCN_RECOVERY*/ #ifdef CONFIG_BCN_XMIT_PROTECT u8 rtw_ap_bcn_queue_empty_check(_adapter *padapter, u32 txbcn_timer_ms) { u32 start_time = rtw_get_current_time(); u8 bcn_queue_empty = _FALSE; do { if (rtw_read16(padapter, REG_TXPKT_EMPTY) & BIT(11)) { bcn_queue_empty = _TRUE; break; } } while (rtw_get_passing_time_ms(start_time) <= (txbcn_timer_ms + 10)); if (bcn_queue_empty == _FALSE) RTW_ERR("%s BCN queue not empty\n", __func__); return bcn_queue_empty; } #endif /*CONFIG_BCN_XMIT_PROTECT*/ #endif /*CONFIG_SWTIMER_BASED_TXBCN*/ static void _rf_type_to_ant_path(enum rf_type rf, enum bb_path *tx, enum bb_path *rx) { if (tx) { switch (rf) { case RF_1T1R: case RF_1T2R: *tx = BB_PATH_A; break; case RF_2T2R: case RF_2T3R: case RF_2T4R: *tx = BB_PATH_AB; break; case RF_3T3R: case RF_3T4R: *tx = BB_PATH_ABC; break; case RF_4T4R: default: *tx = BB_PATH_ABCD; break; } } if (rx) { switch (rf) { case RF_1T1R: *rx = BB_PATH_A; break; case RF_1T2R: case RF_2T2R: *rx = BB_PATH_AB; break; case RF_2T3R: case RF_3T3R: *rx = BB_PATH_ABC; break; case RF_2T4R: case RF_3T4R: case RF_4T4R: default: *rx = BB_PATH_ABCD; break; } } } /** * rtw_hal_get_rf_path() - Get RF path related information * @d: struct dvobj_priv* * @type: RF type, nTnR * @tx: Tx path * @rx: Rx path * * Get RF type, TX path and RX path information. */ void rtw_hal_get_rf_path(struct dvobj_priv *d, enum rf_type *type, enum bb_path *tx, enum bb_path *rx) { struct _ADAPTER *a; u8 val8 = RF_1T1R; enum rf_type rf; a = dvobj_get_primary_adapter(d); rtw_hal_get_hwreg(a, HW_VAR_RF_TYPE, &val8); rf = (enum rf_type)val8; if (type) *type = rf; if (tx || rx) _rf_type_to_ant_path(rf, tx, rx); } #ifdef RTW_CHANNEL_SWITCH_OFFLOAD void rtw_hal_switch_chnl_and_set_bw_offload(_adapter *adapter, u8 central_ch, u8 pri_ch_idx, u8 bw) { u8 h2c[H2C_SINGLE_CHANNELSWITCH_V2_LEN] = {0}; PHAL_DATA_TYPE hal; struct submit_ctx *chsw_sctx; hal = GET_HAL_DATA(adapter); chsw_sctx = &hal->chsw_sctx; SET_H2CCMD_SINGLE_CH_SWITCH_V2_CENTRAL_CH_NUM(h2c, central_ch); SET_H2CCMD_SINGLE_CH_SWITCH_V2_PRIMARY_CH_IDX(h2c, pri_ch_idx); SET_H2CCMD_SINGLE_CH_SWITCH_V2_BW(h2c, bw); rtw_sctx_init(chsw_sctx, 10); rtw_hal_fill_h2c_cmd(adapter, H2C_SINGLE_CHANNELSWITCH_V2, H2C_SINGLE_CHANNELSWITCH_V2_LEN, h2c); rtw_sctx_wait(chsw_sctx, __func__); } #endif /* RTW_CHANNEL_SWITCH_OFFLOAD */