// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2007 - 2017 Realtek Corporation */ #define _HAL_COM_C_ #include #include "hal_com_h2c.h" #include "hal_data.h" void rtw_dump_fw_info(void *sel, struct adapter *adapter) { struct hal_com_data *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 */ #ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE char rtw_phy_para_file_path[PATH_LENGTH_MAX]; #endif void dump_chip_info(struct 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(struct adapter * adapt) { struct hal_com_data *pHalData = GET_HAL_DATA(adapt); 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", __func__, 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: * adapt 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( struct adapter * adapt, char *hw_alpha2, u8 hw_chplan, char *sw_alpha2, u8 sw_chplan, u8 def_chplan, bool AutoLoadFail ) { struct rf_ctl_t *rfctl = adapter_to_rfctl(adapt); struct hal_com_data * pHalData; u8 force_hw_chplan = false; int chplan = -1; const struct country_chplan *country_ent = NULL, *ent; pHalData = GET_HAL_DATA(adapt); /* treat 0xFF as invalid value, bypass hw_chplan & force_hw_chplan parsing */ if (hw_chplan == 0xFF) goto chk_hw_country_code; if (AutoLoadFail) 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) { 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) 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; } bool HAL_IsLegalChannel( struct adapter * Adapter, u32 Channel ) { bool bLegalChannel = true; if (Channel > 14) { if (!is_supported_5g(Adapter->registrypriv.wireless_mode)) { 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)) { 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( struct adapter * Adapter, u8 *mBratesOS, 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( struct adapter * 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( struct adapter * pAdapter, bool 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( struct adapter * pAdapter, bool 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 */ } } bool Hal_MappingOutPipe( struct adapter * pAdapter, u8 NumOutPipe ) { struct registry_priv *pregistrypriv = &pAdapter->registrypriv; bool bWIFICfg = (pregistrypriv->wifi_spec) ? true : false; bool 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(struct adapter *adapt, u8 macid) { if (adapt->hal_func.reqtxrpt) adapt->hal_func.reqtxrpt(adapt, macid); } void rtw_hal_dump_macaddr(void *sel, struct adapter *adapter) { int i; struct 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->adapters[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 } void rtw_restore_mac_addr(struct adapter *adapter) { #ifdef CONFIG_MI_WITH_MBSSID_CAM rtw_mbid_cam_restore(adapter); #else int i; struct adapter *iface; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->adapters[i]; if (iface) rtw_hal_set_hwreg(iface, HW_VAR_MAC_ADDR, adapter_mac_addr(iface)); } #endif rtw_hal_dump_macaddr(RTW_DBGDUMP, adapter); } void rtw_init_hal_com_default_value(struct adapter * Adapter) { struct hal_com_data * 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(struct adapter *adapter) { rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); } int c2h_evt_read_88xx(struct adapter *adapter, u8 *buf) { int ret = _FAIL; int i; u8 trigger; if (!buf) 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 */ } 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)); /* 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 */ #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(struct adapter *adapter, u8 *buf, u16 len) { u8 parse_fail = 0; u8 hdl_here = 0; int 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) ? 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); } } void rtw_hal_c2h_pkt_hdl(struct adapter *adapter, u8 *buf, u16 len) { u8 parse_fail = 0; u8 bypass = 0; int 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; } 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); } } void c2h_iqk_offload(struct adapter *adapter, u8 *data, u8 len) { struct hal_com_data *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)); rtw_sctx_done(&iqk_sctx); } int c2h_iqk_offload_wait(struct adapter *adapter, u32 timeout_ms) { struct hal_com_data *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 int c2h_mac_hidden_rpt_hdl(struct adapter *adapter, u8 *data, u8 len) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); int ret = _FAIL; 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(struct adapter *adapter, u8 *data, u8 len) { 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)); } ret = _SUCCESS; exit: return ret; } static int c2h_mac_hidden_rpt_bt_info_hdl(struct adapter *adapter, u8 val) { struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); hal_spec->bt_ft_ver = (val == 0xff) ? 0 : 1; RTW_INFO("%s bt_ft_ver: %d\n", __func__, hal_spec->bt_ft_ver); return _SUCCESS; } int hal_read_mac_hidden_rpt(struct adapter *adapter) { struct hal_com_data *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}; unsigned long start = rtw_get_current_time(); u32 cnt = 0; u32 timeout_ms = 800; u32 min_cnt = 10; u8 id = C2H_DEFEATURE_RSVD; int i; 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); /* 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); c2h_mac_hidden_rpt_bt_info_hdl(adapter, rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1)); if (ret_fwdl == _SUCCESS && id == C2H_MAC_HIDDEN_RPT) ret = _SUCCESS; if ((hci_type == RTW_USB || hci_type == RTW_PCIE) && !rtw_is_hw_init_completed(adapter)) rtw_hal_power_off(adapter); 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; } int c2h_defeature_dbg_hdl(struct adapter *adapter, u8 *data, u8 len) { 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 int rtw_hal_h2c_customer_str_req(struct 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(struct adapter *adapter, u8 *data, u8 len) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); int ret = _FAIL; 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) { if (dvobj->customer_str_sctx->status != RTW_SCTX_SUBMITTED) RTW_WARN("%s invalid sctx.status:%d\n", __func__, dvobj->customer_str_sctx->status); 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(struct adapter *adapter, u8 *data, u8 len) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); int ret = _FAIL; 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) { if (dvobj->customer_str_sctx->status != RTX_SCTX_CSTR_WAIT_RPT2) RTW_WARN("%s rpt not ready\n", __func__); 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 */ int rtw_hal_customer_str_read(struct adapter *adapter, u8 *cs) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct submit_ctx sctx; int ret = _SUCCESS; _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); if (dvobj->customer_str_sctx) 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) memcpy(cs, dvobj->customer_str, RTW_CUSTOMER_STR_LEN); else ret = _FAIL; _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); exit: return ret; } int rtw_hal_h2c_customer_str_write(struct 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}; int ret; SET_H2CCMD_CUSTOMER_STR_W1_EN(h2c_data_w1, 1); memcpy(H2CCMD_CUSTOMER_STR_W1_BYTE0(h2c_data_w1), cs, 6); SET_H2CCMD_CUSTOMER_STR_W2_EN(h2c_data_w2, 1); memcpy(H2CCMD_CUSTOMER_STR_W2_BYTE6(h2c_data_w2), cs + 6, 6); SET_H2CCMD_CUSTOMER_STR_W3_EN(h2c_data_w3, 1); 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 */ int rtw_hal_customer_str_write(struct adapter *adapter, const u8 *cs) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct submit_ctx sctx; int ret = _SUCCESS; _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); if (dvobj->customer_str_sctx) { 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 (memcmp(cs, dvobj->customer_str, RTW_CUSTOMER_STR_LEN)) { 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; } void rtw_hal_update_sta_wset(struct 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; } static void rtw_hal_update_sta_mimo_type(struct 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); } static void rtw_hal_update_sta_smps_cap(struct adapter *adapter, struct sta_info *psta) { /*Spatial Multiplexing Power Save*/ 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(struct adapter *adapter, unsigned char network_type) { return (network_type & WIRELESS_11B) ? RATR_INX_WIRELESS_B : RATR_INX_WIRELESS_G; } static void rtw_hal_update_sta_rate_mask(struct adapter * adapt, struct sta_info *psta) { struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapt); u8 i, rf_type, tx_nss; u64 tx_ra_bitmap = 0; if (!psta) 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); } rtw_hal_get_hwreg(adapt, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); if (psta->htpriv.ht_option) { /* n mode ra_bitmap */ /* Handling SMPS mode for AP MODE only*/ if (check_fwstate(&adapt->mlmepriv, WIFI_AP_STATE)) { /*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); } 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(struct adapter * adapt, struct sta_info *psta) { rtw_hal_update_sta_mimo_type(adapt, psta); rtw_hal_update_sta_smps_cap(adapt, psta); rtw_hal_update_sta_rate_mask(adapt, 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(struct adapter *adapter, u8 addr) { _mutex *mutex = &adapter_to_dvobj(adapter)->cam_ctl.sec_cam_access_mutex; u32 rdata; u32 cnt = 0; unsigned long 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(struct adapter *adapter, u8 addr, u32 wdata) { _mutex *mutex = &adapter_to_dvobj(adapter)->cam_ctl.sec_cam_access_mutex; u32 cnt = 0; unsigned long 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(struct adapter *adapter, u8 id, u8 *ctrl, u8 *mac, u8 *key) { 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) memcpy(ctrl, (u8 *)(&rdata), 2); if (mac) memcpy(mac, ((u8 *)(&rdata)) + 2, 2); break; case 1: if (mac) memcpy(mac + 2, (u8 *)(&rdata), 4); break; default: if (key) memcpy(key + (i - 2) * 4, (u8 *)(&rdata), 4); break; } } exit: return; } void rtw_sec_write_cam_ent(struct adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) { unsigned int i; int j; u8 addr; u32 wdata; j = 7; 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(struct adapter *adapter, u8 id) { u8 addr; addr = (id << 3); rtw_sec_write_cam(adapter, addr, 0); } bool rtw_sec_read_cam_is_gk(struct 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_MI_WITH_MBSSID_CAM void rtw_mbid_cam_init(struct dvobj_priv *dvobj) { struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; spin_lock_init(&mbid_cam_ctl->lock); mbid_cam_ctl->bitmap = 0; ATOMIC_SET(&mbid_cam_ctl->mbid_entry_num, 0); memset(&dvobj->mbid_cam_cache, 0, sizeof(dvobj->mbid_cam_cache)); } void rtw_mbid_cam_deinit(struct dvobj_priv *dvobj) { } void rtw_mbid_cam_reset(struct adapter *adapter) { unsigned long 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; 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(struct 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 && !memcmp(dvobj->mbid_cam_cache[i].mac_addr, mac_addr, ETH_ALEN)) { 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(struct adapter *adapter, u8 *mac_addr) { unsigned long 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(struct 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(struct adapter *adapter, u8 iface_id) { unsigned long 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(struct adapter *adapter) { unsigned long 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(struct 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(struct adapter *adapter, struct mbid_cam_cache *pmbid_cam, u8 *mac_addr) { if (adapter && pmbid_cam && mac_addr) { 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) { memset(pmbid_cam->mac_addr, 0, ETH_ALEN); pmbid_cam->iface_id = CONFIG_IFACE_NUMBER; } } u8 rtw_mbid_camid_alloc(struct adapter *adapter, u8 *mac_addr) { unsigned long 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 CONFIG_MI_WITH_MBSSID_CAM 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(struct adapter *adapter, u8 *mac_addr) { unsigned long 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(struct adapter *adapter, u8 *mac_addr, u8 camid) { unsigned long 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) { 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 CONFIG_MI_WITH_MBSSID_CAM 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(struct adapter *adapter, u8 mbss_canid) { unsigned long 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, struct adapter *adapter) { unsigned long irqL; u8 i; struct 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->adapters[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(struct adapter *adapt, u8 cam_addr, u8 *mac) { u8 poll = 1; u8 cam_ready = false; u32 cam_data1 = 0; u16 cam_data2 = 0; if (RTW_CANNOT_RUN(adapt)) return; rtw_write32(adapt, REG_MBIDCAMCFG_2, BIT_MBIDCAM_POLL | ((cam_addr & MBIDCAM_ADDR_MASK) << MBIDCAM_ADDR_SHIFT)); do { if (0 == (rtw_read32(adapt, REG_MBIDCAMCFG_2) & BIT_MBIDCAM_POLL)) { cam_ready = true; break; } poll++; } while ((poll % 10) != 0 && !RTW_CANNOT_RUN(adapt)); if (cam_ready) { cam_data1 = rtw_read32(adapt, 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(adapt, 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, struct adapter *adapter) { /*unsigned long 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); 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(struct adapter *adapt, 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(adapt, HW_VAR_MBSSID_CAM_WRITE, (u8 *)cam_val); } static void clear_mbssid_cam(struct adapter *adapt, u8 cam_addr) { rtw_hal_set_hwreg(adapt, HW_VAR_MBSSID_CAM_CLEAR, &cam_addr); } static void enable_mbssid_cam(struct 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(struct 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 CONFIG_MI_WITH_MBSSID_CAM 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_MI_WITH_MBSSID_CAM*/ #ifdef CONFIG_MI_WITH_MBSSID_CAM void rtw_hal_set_macaddr_mbid(struct adapter *adapter, u8 *mac_addr) { /* 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); } } void rtw_hal_change_macaddr_mbid(struct 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); } #endif/*#ifdef CONFIG_MI_WITH_MBSSID_CAM*/ static void rtw_hal_set_macaddr_port(struct adapter *adapter, u8 *val) { u8 idx = 0; u32 reg_macid = 0; if (!val) return; RTW_INFO("%s "ADPT_FMT"- hw port(%d) mac_addr ="MAC_FMT"\n", __func__, ADPT_ARG(adapter), adapter->hw_port, MAC_ARG(val)); switch (adapter->hw_port) { case HW_PORT0: default: reg_macid = REG_MACID; break; case HW_PORT1: reg_macid = REG_MACID1; break; } for (idx = 0; idx < 6; idx++) rtw_write8(GET_PRIMARY_ADAPTER(adapter), (reg_macid + idx), val[idx]); } static void rtw_hal_get_macaddr_port(struct adapter *adapter, u8 *mac_addr) { u8 idx = 0; u32 reg_macid = 0; if (!mac_addr) return; memset(mac_addr, 0, ETH_ALEN); switch (adapter->hw_port) { case HW_PORT0: default: reg_macid = REG_MACID; break; case HW_PORT1: reg_macid = REG_MACID1; break; } for (idx = 0; idx < 6; idx++) mac_addr[idx] = rtw_read8(GET_PRIMARY_ADAPTER(adapter), (reg_macid + idx)); 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(struct adapter *adapter, u8 *val) { 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; } for (idx = 0 ; idx < 6; idx++) rtw_write8(adapter, (reg_bssid + idx), val[idx]); 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(struct 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(struct 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(struct adapter *adapter, u32 check_bit) { struct hal_com_data * 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(struct adapter *adapter, u32 add) { struct hal_com_data * 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(struct adapter *adapter, u32 clear) { struct hal_com_data * 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(struct adapter *adapter, u8 self_action) { struct hal_com_data *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; 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; #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) || 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(struct 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(struct adapter *adapter, u8 *net_type) { 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; default: RTW_INFO("[WARN] "ADPT_FMT"- invalid hw port -%d\n", ADPT_ARG(adapter), adapter->hw_port); rtw_warn_on(1); break; } } #if defined(CONFIG_MI_WITH_MBSSID_CAM) && defined(CONFIG_MI_WITH_MBSSID_CAM) /*For 2 hw ports - 88E/92E/8812/8821/8723B*/ static u8 rtw_hal_net_type_decision(struct 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(struct adapter *adapter, u8 net_type) { u8 val8 = 0; switch (adapter->hw_port) { case HW_PORT0: #if defined(CONFIG_MI_WITH_MBSSID_CAM) && defined(CONFIG_MI_WITH_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; default: RTW_INFO("[WARN] "ADPT_FMT"- invalid hw port -%d\n", ADPT_ARG(adapter), adapter->hw_port); rtw_warn_on(1); break; } } static void hw_var_set_bcn_interval(struct adapter *a, u16 interval) { RTW_ERR(FUNC_ADPT_FMT ": Not implemented yet!!\n", FUNC_ADPT_ARG(a)); rtw_warn_on(1); } void hw_var_port_switch(struct 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]; struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct 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); /* 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 */ /* always enable port0 beacon function for PSTDMA */ bcn_ctrl_1 |= EN_BCN_FUNCTION; /* always disable port1 beacon function for PSTDMA */ 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->adapters[IFACE_ID1]; else if (adapter->iface_id == IFACE_ID1) iface = dvobj->adapters[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)); } #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 int rtw_hal_set_default_port_id_cmd(struct adapter *adapter, u8 mac_id) { int 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; } int rtw_set_default_port_id(struct adapter *adapter) { int 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)) { 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)) { } else { } return ret; } int rtw_set_ps_rsvd_page(struct adapter *adapter) { int 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 /* * 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: */ int rtw_hal_set_FwMediaStatusRpt_cmd(struct 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; int 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; 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 int rtw_hal_set_FwMediaStatusRpt_single_cmd(struct 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 int rtw_hal_set_FwMediaStatusRpt_range_cmd(struct 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); } static void rtw_hal_set_FwRsvdPage_cmd(struct adapter * adapt, struct rsvd_page * rsvdpageloc) { 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_RSVD_PAGE_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp); SET_H2CCMD_RSVD_PAGE_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); SET_H2CCMD_RSVD_PAGE_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); SET_H2CCMD_RSVD_PAGE_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); SET_H2CCMD_RSVD_PAGE_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull); ret = rtw_hal_fill_h2c_cmd(adapt, H2C_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); } int rtw_hal_get_rsvd_page(struct 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; } 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); memcpy(buffer + (i * 8), &data_low, sizeof(data_low)); memcpy(buffer + ((i * 8) + 4), &data_high, sizeof(data_high)); } rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, 0x0); rst = true; return rst; } void rtw_dump_rsvd_page(void *sel, struct 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 = vzalloc(buf_size); if (buffer) { rtw_hal_get_rsvd_page(adapter, page_offset, page_num, buffer, buf_size); RTW_DUMP_SEL(sel, buffer, buf_size); vfree(buffer); } 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"); } void rtw_hal_construct_beacon(struct adapter *adapt, u8 *pframe, u32 *pLength) { struct rtw_ieee80211_hdr *pwlanhdr; __le16 *fctrl; u32 rate_len, pktlen; struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* RTW_INFO("%s\n", __func__); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); memcpy(pwlanhdr->addr2, adapter_mac_addr(adapt), ETH_ALEN); 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 */ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); pframe += 2; pktlen += 2; /* capability info: 2 bytes */ 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(struct ndis_802_11_fixed_ies); memcpy(pframe, cur_network->IEs + sizeof(struct 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", __func__, pktlen); */ } static void rtw_hal_construct_PSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength) { struct rtw_ieee80211_hdr *pwlanhdr; __le16 *fctrl; struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); /* RTW_INFO("%s\n", __func__); */ 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. */ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); /* TA. */ memcpy(pwlanhdr->addr2, adapter_mac_addr(adapt), ETH_ALEN); *pLength = 16; } void rtw_hal_construct_NullFunctionData( struct adapter * adapt, u8 *pframe, u32 *pLength, u8 *StaAddr, u8 bQoS, u8 AC, u8 bEosp, u8 bForcePowerSave) { struct rtw_ieee80211_hdr *pwlanhdr; __le16 *fctrl; u32 pktlen; struct mlme_priv *pmlmepriv = &adapt->mlmepriv; struct wlan_network *cur_network = &pmlmepriv->cur_network; struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u8 bssid[ETH_ALEN]; /* RTW_INFO("%s:%d\n", __func__, bForcePowerSave); */ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; if (bForcePowerSave) SetPwrMgt(fctrl); if (!StaAddr) { memcpy(bssid, adapter_mac_addr(adapt), ETH_ALEN); StaAddr = bssid; } switch (cur_network->network.InfrastructureMode) { case Ndis802_11Infrastructure: SetToDs(fctrl); memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); memcpy(pwlanhdr->addr2, adapter_mac_addr(adapt), ETH_ALEN); memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); break; case Ndis802_11APMode: SetFrDs(fctrl); memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); memcpy(pwlanhdr->addr3, adapter_mac_addr(adapt), ETH_ALEN); break; case Ndis802_11IBSS: default: memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); memcpy(pwlanhdr->addr2, adapter_mac_addr(adapt), ETH_ALEN); memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); break; } SetSeqNum(pwlanhdr, 0); set_duration(pwlanhdr, 0); if (bQoS) { 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; } static void rtw_hal_construct_ProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) { struct rtw_ieee80211_hdr *pwlanhdr; __le16 *fctrl; u8 *mac, *bssid; u32 pktlen; struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); /*RTW_INFO("%s\n", __func__);*/ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; mac = adapter_mac_addr(adapt); bssid = cur_network->MacAddress; fctrl = &(pwlanhdr->frame_ctl); *(fctrl) = 0; memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); memcpy(pwlanhdr->addr2, mac, ETH_ALEN); 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; memcpy(pframe, cur_network->IEs, cur_network->IELength); pframe += cur_network->IELength; pktlen += cur_network->IELength; *pLength = pktlen; } /* * 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 */ static void _rtw_hal_set_fw_rsvd_page(struct adapter *adapter, bool finished, u8 *page_num) { struct hal_com_data * 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; u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength = 0; u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 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; struct rsvd_page RsvdPageLoc; pHalData = GET_HAL_DATA(adapter); 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", __func__); *page_num = 0xFF; return; } } else { if (pwrctl->wowlan_mode || pwrctl->wowlan_ap_mode) 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) { RTW_ERR("%s: alloc ReservedPagePacket fail!\n", __func__); return; } ReservedPagePacket = pcmdframe->buf_addr; } memset(&RsvdPageLoc, 0, sizeof(struct rsvd_page)); /* 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); if (pwrctl->wowlan_ap_mode) { /* (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); 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); if (!pwrctl->wowlan_mode || pwrctl->wowlan_in_resume) { /* 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); } /* 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); if (!pwrctl->wowlan_mode || pwrctl->wowlan_in_resume) { /* 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); } TotalPacketLen = BufIndex + QosNullLength; TotalPacketLen -= TxDescOffset; download_page: if (page_num) { *page_num = TotalPageNum; rtw_mfree(ReservedPagePacket, MAX_CMDBUF_SZ); ReservedPagePacket = NULL; return; } RTW_INFO("%s PageNum(%d), pktlen(%d)\n", __func__, TotalPageNum, TotalPacketLen); if (TotalPacketLen > MaxRsvdPageBufSize) { RTW_ERR("%s(ERROR): rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", __func__, 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; dump_mgntframe_and_wait(adapter, pcmdframe, 100); } RTW_INFO("%s: Set RSVD page location to Fw ,TotalPacketLen(%d), TotalPageNum(%d)\n", __func__, TotalPacketLen, TotalPageNum); if (check_fwstate(pmlmepriv, _FW_LINKED)) { rtw_hal_set_FwRsvdPage_cmd(adapter, &RsvdPageLoc); } 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(struct adapter *adapter, u8 variable, u8 *val) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); struct hal_com_data *hal_data = GET_HAL_DATA(adapter); u16 value_rxfltmap2; int i; struct adapter *iface; /* not to receive data frame */ value_rxfltmap2 = 0; 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->adapters[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 (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->adapters[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 (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(struct 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(struct 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(struct adapter * adapt) { struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; #if defined(CONFIG_MI_WITH_MBSSID_CAM) RTW_INFO("[Warn] %s "ADPT_FMT" enter func\n", __func__, ADPT_ARG(adapt)); rtw_warn_on(1); return; #endif if (!pmlmeext->en_hw_update_tsf) return; /* check RCR */ if (!rtw_hal_rcr_check(adapt, RCR_CBSSID_BCN)) return; /* enable hw update tsf function for non-AP and non-Mesh */ if (rtw_linked_check(adapt) && !MLME_IS_AP(adapt) && !MLME_IS_MESH(adapt) ) { #ifdef CONFIG_CONCURRENT_MODE if (adapt->hw_port == HW_PORT1) rtw_write8(adapt, REG_BCN_CTRL_1, rtw_read8(adapt, REG_BCN_CTRL_1) & (~DIS_TSF_UDT)); else #endif rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) & (~DIS_TSF_UDT)); } pmlmeext->en_hw_update_tsf = false; } static void hw_var_set_correct_tsf(struct 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; struct adapter *iface; for (i = 0; i < dvobj->iface_nums; i++) { iface = dvobj->adapters[i]; if (!iface) continue; if (iface == adapter) continue; if ((MLME_IS_AP(iface) || MLME_IS_MESH(iface)) && check_fwstate(&iface->mlmepriv, WIFI_ASOC_STATE) ) { 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*/ } #if defined(CONFIG_FW_MULTI_PORT_SUPPORT) /* For multi-port support, driver needs to inform the port ID to FW for btc operations */ int rtw_hal_set_wifi_port_id_cmd(struct 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(struct adapter *adapter, u8 variable, u8 *val) { struct hal_com_data *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_MI_WITH_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; struct 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)) { /* 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; case HW_VAR_MLME_SITESURVEY: hw_var_set_mlme_sitesurvey(adapter, variable, val); if (hal_data->EEPROMBluetoothCoexist == 1) rtw_btcoex_ScanNotify(adapter, *val ? true : false); 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; case HW_VAR_ENABLE_RX_BAR: if (*val) { /* 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: break; } return ret; } void GetHwReg(struct adapter *adapter, u8 variable, u8 *val) { struct hal_com_data *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: break; } } static u32 _get_page_size(struct adapter *a) { return PAGE_SIZE_128; } u8 SetHalDefVar(struct adapter *adapter, enum hal_def_variable variable, void *value) { struct hal_com_data *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; case HAL_DEF_DBG_DIS_PWT: hal_data->bDisableTXPowerTraining = *((u8 *)value); break; default: RTW_PRINT("%s: [WARNING] hal_def_variable(%d) not defined!\n", __func__, variable); bResult = _FAIL; break; } return bResult; } u8 GetHalDefVar(struct adapter *adapter, enum hal_def_variable variable, void *value) { struct hal_com_data *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_DBG_DIS_PWT: *(u8 *)value = hal_data->bDisableTXPowerTraining; 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; default: RTW_PRINT("%s: [WARNING] hal_def_variable(%d) not defined!\n", __func__, variable); bResult = _FAIL; break; } return bResult; } bool 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( 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. * */ bool GetHexValueFromString( char *szStr, u32 *pu4bVal, u32 *pu4bMove ) { char *szScan = szStr; /* Check input parameter. */ if (!szStr || !pu4bVal || !pu4bMove) { RTW_INFO("GetHexValueFromString(): Invalid input 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; } bool GetFractionValueFromString( char *szStr, u8 *pInteger, u8 *pFraction, 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 " */ /* ". * */ bool IsCommentString( char *szStr ) { if (*szStr == '/' && *(szStr + 1) == '/') return true; else return false; } bool GetU1ByteIntegerFromStringInDecimal( char *Str, 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 */ bool ParseQualifiedString( char *In, u32 *Start, char *Out, char LeftQualifier, 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; } bool 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(struct adapter *adapter) { struct dvobj_priv *psdpriv = adapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; struct hal_com_data *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(struct adapter *adapt, u8 benable) { struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(adapt); if (adapt->bLinkInfoDump == benable) return; RTW_INFO("%s %s\n", __func__, (benable) ? "enable" : "disable"); if (benable) { pwrctrlpriv->org_power_mgnt = pwrctrlpriv->power_mgnt;/* keep org value */ rtw_pm_set_lps(adapt, PS_MODE_ACTIVE); pwrctrlpriv->ips_org_mode = pwrctrlpriv->ips_mode;/* keep org value */ rtw_pm_set_ips(adapt, IPS_NONE); } else { rtw_pm_set_ips(adapt, pwrctrlpriv->ips_org_mode); rtw_pm_set_lps(adapt, pwrctrlpriv->org_power_mgnt); } adapt->bLinkInfoDump = benable ; } void rtw_store_phy_info(struct adapter *adapt, union recv_frame *prframe) { u8 isCCKrate, rf_path , dframe_type; u8 *ptr; struct recv_priv *precvpriv = &(adapt->recvpriv); struct hal_com_data * pHalData = GET_HAL_DATA(adapt); struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; struct phydm_phyinfo_struct *p_phy_info = &pattrib->phy_info; struct rx_raw_rssi *psample_pkt_rssi = &adapt->recvpriv.raw_rssi_info; psample_pkt_rssi->data_rate = pattrib->data_rate; ptr = prframe->u.hdr.rx_data; dframe_type = GetFrameType(ptr); 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]; } } } } int check_phy_efuse_tx_power_info_valid(struct adapter * adapt) { struct hal_com_data * pHalData = GET_HAL_DATA(adapt); u8 *pContent = pHalData->efuse_eeprom_data; int index = 0; u16 tx_index_offset = 0x0000; switch (rtw_get_chip_type(adapt)) { case RTL8723B: tx_index_offset = EEPROM_TX_PWR_INX_8723B; break; case RTL8703B: tx_index_offset = EEPROM_TX_PWR_INX_8703B; break; case RTL8723D: tx_index_offset = EEPROM_TX_PWR_INX_8723D; break; case RTL8188E: tx_index_offset = EEPROM_TX_PWR_INX_88E; break; case RTL8188F: tx_index_offset = EEPROM_TX_PWR_INX_8188F; break; case RTL8192E: tx_index_offset = EEPROM_TX_PWR_INX_8192E; break; case RTL8821: tx_index_offset = EEPROM_TX_PWR_INX_8821; break; case RTL8812: tx_index_offset = EEPROM_TX_PWR_INX_8812; break; case RTL8814A: tx_index_offset = EEPROM_TX_PWR_INX_8814; break; case RTL8822B: tx_index_offset = EEPROM_TX_PWR_INX_8822B; break; case RTL8821C: tx_index_offset = EEPROM_TX_PWR_INX_8821C; break; default: tx_index_offset = 0x0010; break; } /* TODO: chacking length by ICs */ for (index = 0 ; index < 11 ; index++) { if (pContent[tx_index_offset + index] == 0xFF) return false; } return true; } int hal_efuse_macaddr_offset(struct adapter *adapter) { u8 interface_type = 0; int addr_offset = -1; interface_type = rtw_get_intf_type(adapter); switch (rtw_get_chip_type(adapter)) { 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; } 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(struct adapter * adapt, u8 *mac_addr) { int ret = _FAIL; int addr_offset; addr_offset = hal_efuse_macaddr_offset(adapt); if (addr_offset == -1) goto exit; ret = rtw_efuse_map_read(adapt, addr_offset, ETH_ALEN, mac_addr); exit: return ret; } void rtw_dump_cur_efuse(struct adapter * adapt) { int mapsize =0; struct hal_com_data *hal_data = GET_HAL_DATA(adapt); EFUSE_GetEfuseDefinition(adapt, 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(struct adapter * adapt) { struct hal_com_data *hal_data = GET_HAL_DATA(adapt); u32 ret = false; u32 maplen = 0; EFUSE_GetEfuseDefinition(adapt, 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(adapt); return ret; } u32 Hal_ReadMACAddrFromFile(struct adapter * adapt, u8 *mac_addr) { struct hal_com_data *hal_data = GET_HAL_DATA(adapt); u32 ret = _FAIL; if (rtw_read_macaddr_from_file(WIFIMAC_PATH, mac_addr) == _SUCCESS && !rtw_check_invalid_mac_address(mac_addr, true) ) { 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(struct adapter *adapter, bool autoload_fail) { struct hal_com_data *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 (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; } /* check hw pg data */ if (hw_addr && !rtw_check_invalid_mac_address(hw_addr, true)) { 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) { memcpy(hal_data->EEPROMMACAddr, addr, ETH_ALEN); goto exit; } #endif memset(hal_data->EEPROMMACAddr, 0, ETH_ALEN); ret = _FAIL; exit: return ret; } void rtw_bb_rf_gain_offset(struct adapter *adapt) { struct hal_com_data *pHalData = GET_HAL_DATA(adapt); struct registry_priv *registry_par = &adapt->registrypriv; struct kfree_data_t *kfree_data = &pHalData->kfree_data; if (registry_par->RegPwrTrimEnable == 2) { RTW_INFO("Registry kfree default force disable.\n"); return; } /* TODO: call this when channel switch */ if (kfree_data->flag & KFREE_FLAG_ON) rtw_rf_apply_tx_gain_offset(adapt, 6); /* input ch6 to select BB_GAIN_2G */ } bool kfree_data_is_bb_gain_empty(struct kfree_data_t *data) { 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; return 1; } /* To avoid RX affect TX throughput */ void dm_DynamicUsbTxAgg(struct adapter *adapt, u8 from_timer) { } /* bus-agg check for SoftAP mode */ inline u8 rtw_hal_busagg_qsel_check(struct adapter *adapt, u8 pre_qsel, u8 next_qsel) { u8 chk_rst = _SUCCESS; if (!MLME_IS_AP(adapt) && !MLME_IS_MESH(adapt)) return chk_rst; if (((pre_qsel == QSLT_HIGH) || ((next_qsel == QSLT_HIGH))) && (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(struct adapter *adapt, 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(adapt, 0x106); rtw_write8(adapt, 0x106, 0x69); RTW_INFO("0x106: 0x%02x\n", val); base = rtw_read8(adapt, 0x209); RTW_INFO("0x209: 0x%02x\n", base); addr = ((base)*page_size) / 8; for (i = 0 ; i < page_num * count ; i += 2) { rtw_write32(adapt, 0x140, addr + i); printk(" %08x %08x ", rtw_read32(adapt, 0x144), rtw_read32(adapt, 0x148)); rtw_write32(adapt, 0x140, addr + i + 1); printk(" %08x %08x\n", rtw_read32(adapt, 0x144), rtw_read32(adapt, 0x148)); } } s8 rtw_hal_ch_sw_iqk_info_search(struct adapter *adapt, u8 central_chnl, u8 bw_mode) { struct hal_com_data *pHalData = GET_HAL_DATA(adapt); 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(struct adapter *adapt) { struct hal_com_data *pHalData = GET_HAL_DATA(adapt); s8 res; u8 i; /* If it's an existed record, overwrite it */ res = rtw_hal_ch_sw_iqk_info_search(adapt, pHalData->current_channel, pHalData->current_channel_bw); if ((res >= 0) && (res < MAX_IQK_INFO_BACKUP_CHNL_NUM)) { rtw_hal_set_hwreg(adapt, 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(adapt, 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++) memcpy(&(pHalData->iqk_reg_backup[i - 1]), &(pHalData->iqk_reg_backup[i]), sizeof(struct hal_iqk_reg_backup)); rtw_hal_set_hwreg(adapt, 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(struct adapter *adapt, u8 ch_sw_use_case) { rtw_hal_set_hwreg(adapt, HW_VAR_CH_SW_IQK_INFO_RESTORE, &ch_sw_use_case); } void rtw_dump_mac_rx_counters(struct adapter *adapt, 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; } phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x3); mac_cck_ok = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x0); mac_ofdm_ok = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x6); mac_ht_ok = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ mac_vht_ok = 0; phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x4); mac_cck_err = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x1); mac_ofdm_err = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x7); mac_ht_err = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ mac_vht_err = 0; phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x5); mac_cck_fa = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x2); mac_ofdm_fa = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x9); mac_ht_fa = phy_query_mac_reg(adapt, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ /* Mac_DropPacket */ rtw_write32(adapt, REG_RXERR_RPT, (rtw_read32(adapt, REG_RXERR_RPT) & 0x0FFFFFFF) | Mac_DropPacket); DropPacket = rtw_read32(adapt, 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(struct adapter *adapt) { /* If no packet rx, MaxRx clock be gating ,BIT_DISGCLK bit19 set 1 for fix*/ phy_set_mac_reg(adapt, REG_RCR, BIT19, 0x1); /* reset mac counter */ phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT27, 0x1); phy_set_mac_reg(adapt, REG_RXERR_RPT, BIT27, 0x0); } void rtw_dump_phy_rx_counters(struct adapter *adapt, 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; } cckok = phy_query_bb_reg(adapt, 0xF88, bMaskDWord); ofdmok = phy_query_bb_reg(adapt, 0xF94, bMaskLWord); htok = phy_query_bb_reg(adapt, 0xF90, bMaskLWord); vht_ok = 0; cckcrc = phy_query_bb_reg(adapt, 0xF84, bMaskDWord); ofdmcrc = phy_query_bb_reg(adapt, 0xF94, bMaskHWord); htcrc = phy_query_bb_reg(adapt, 0xF90, bMaskHWord); vht_err = 0; OFDM_FA = phy_query_bb_reg(adapt, 0xCF0, bMaskLWord) + phy_query_bb_reg(adapt, 0xCF2, bMaskLWord) + phy_query_bb_reg(adapt, 0xDA2, bMaskLWord) + phy_query_bb_reg(adapt, 0xDA4, bMaskLWord) + phy_query_bb_reg(adapt, 0xDA6, bMaskLWord) + phy_query_bb_reg(adapt, 0xDA8, bMaskLWord); CCK_FA = (rtw_read8(adapt, 0xA5B) << 8) | (rtw_read8(adapt, 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(struct adapter *adapt) { } void rtw_reset_phy_rx_counters(struct adapter *adapt) { phy_set_bb_reg(adapt, 0xF14, BIT16, 0x1); rtw_msleep_os(10); phy_set_bb_reg(adapt, 0xF14, BIT16, 0x0); phy_set_bb_reg(adapt, 0xD00, BIT27, 0x1);/* reset OFDA FA counter */ phy_set_bb_reg(adapt, 0xC0C, BIT31, 0x1);/* reset OFDA FA counter */ phy_set_bb_reg(adapt, 0xD00, BIT27, 0x0); phy_set_bb_reg(adapt, 0xC0C, BIT31, 0x0); phy_set_bb_reg(adapt, 0xA2C, BIT15, 0x0);/* reset CCK FA counter */ phy_set_bb_reg(adapt, 0xA2C, BIT15, 0x1); } u8 rtw_get_current_tx_sgi(struct adapter *adapt, struct sta_info *psta) { u8 curr_tx_sgi = 0; struct ra_sta_info *ra_info; if (!psta) return curr_tx_sgi; ra_info = &psta->cmn.ra_info; curr_tx_sgi = ((ra_info->curr_tx_rate) & 0x80) >> 7; return curr_tx_sgi; } u8 rtw_get_current_tx_rate(struct adapter *adapt, struct sta_info *psta) { u8 rate_id = 0; struct ra_sta_info *ra_info; if (!psta) return rate_id; ra_info = &psta->cmn.ra_info; rate_id = ra_info->curr_tx_rate & 0x7f; return rate_id; } void update_IOT_info(struct adapter *adapt) { struct mlme_ext_priv *pmlmeext = &adapt->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(adapt, 0x4cc, 0xffff); */ /* rtw_write16(adapt, 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(struct adapter *adapter, u8 crystal_cap) { crystal_cap = crystal_cap & 0x3F; switch (rtw_get_chip_type(adapter)) { 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; default: rtw_warn_on(1); } } int hal_spec_init(struct adapter *adapter) { u8 interface_type = 0; int ret = _SUCCESS; interface_type = rtw_get_intf_type(adapter); switch (rtw_get_chip_type(adapter)) { case RTL8723D: init_hal_spec_8723d(adapter); break; 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, struct 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"); } inline bool hal_chk_band_cap(struct adapter *adapter, u8 cap) { return GET_HAL_SPEC(adapter)->band_cap & cap; } inline bool hal_chk_bw_cap(struct adapter *adapter, u8 cap) { return GET_HAL_SPEC(adapter)->bw_cap & cap; } inline bool hal_chk_proto_cap(struct adapter *adapter, u8 cap) { return GET_HAL_SPEC(adapter)->proto_cap & cap; } inline bool hal_chk_wl_func(struct adapter *adapter, u8 func) { return GET_HAL_SPEC(adapter)->wl_func & func; } inline bool hal_is_band_support(struct adapter *adapter, u8 band) { return GET_HAL_SPEC(adapter)->band_cap & band_to_band_cap(band); } inline bool hal_is_bw_support(struct adapter *adapter, u8 bw) { return GET_HAL_SPEC(adapter)->bw_cap & ch_width_to_bw_cap(bw); } inline bool hal_is_wireless_mode_support(struct 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(struct 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(struct adapter *adapt, u8 hw_port, u64 tsf) { if (hw_port == HW_PORT0) { /*disable related TSF function*/ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) & (~EN_BCN_FUNCTION)); rtw_write32(adapt, REG_TSFTR, tsf); rtw_write32(adapt, REG_TSFTR + 4, tsf >> 32); /*enable related TSF function*/ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) | EN_BCN_FUNCTION); } else if (hw_port == HW_PORT1) { /*disable related TSF function*/ rtw_write8(adapt, REG_BCN_CTRL_1, rtw_read8(adapt, REG_BCN_CTRL_1) & (~EN_BCN_FUNCTION)); rtw_write32(adapt, REG_TSFTR1, tsf); rtw_write32(adapt, REG_TSFTR1 + 4, tsf >> 32); /*enable related TSF function*/ rtw_write8(adapt, REG_BCN_CTRL_1, rtw_read8(adapt, REG_BCN_CTRL_1) | EN_BCN_FUNCTION); } else RTW_INFO("%s-[WARN] "ADPT_FMT" invalid hw_port:%d\n", __func__, ADPT_ARG(adapt), hw_port); } void ResumeTxBeacon(struct adapter *adapt) { #ifdef CONFIG_MI_WITH_MBSSID_CAM #else rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, rtw_read8(adapt, REG_FWHW_TXQ_CTRL + 2) | BIT(6)); /* TBTT hold time: 0x540[19:8] */ rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, TBTT_PROHIBIT_HOLD_TIME & 0xFF); rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, (rtw_read8(adapt, REG_TBTT_PROHIBIT + 2) & 0xF0) | (TBTT_PROHIBIT_HOLD_TIME >> 8)); #endif } void StopTxBeacon(struct adapter *adapt) { #ifdef CONFIG_MI_WITH_MBSSID_CAM #else rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, rtw_read8(adapt, REG_FWHW_TXQ_CTRL + 2) & (~BIT6)); /* TBTT hold time: 0x540[19:8] */ rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, TBTT_PROHIBIT_HOLD_TIME_STOP_BCN & 0xFF); rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, (rtw_read8(adapt, 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(struct 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 } } #endif #ifdef CONFIG_PHY_CAPABILITY_QUERY void rtw_dump_phy_cap_by_phydmapi(void *sel, struct adapter *adapter) { struct hal_com_data *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]*/ } #else static void rtw_dump_phy_cap_by_hal(void *sel, struct 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", (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", (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", (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", (phy_cap) ? "Supported" : "N/A"); } #endif void rtw_dump_phy_cap(void *sel, struct 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 RTW_CHANNEL_SWITCH_OFFLOAD void rtw_hal_switch_chnl_and_set_bw_offload(struct adapter *adapter, u8 central_ch, u8 pri_ch_idx, u8 bw) { u8 h2c[H2C_SINGLE_CHANNELSWITCH_V2_LEN] = {0}; struct hal_com_data * 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, 100); 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 */