/****************************************************************************** * * Copyright(c) 2007 - 2017 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ /* ************************************************************ * include files * ************************************************************ */ #include "mp_precomp.h" #include "phydm_precomp.h" #ifdef PHYDM_SUPPORT_RSSI_MONITOR #ifdef PHYDM_3RD_REFORM_RSSI_MONOTOR void phydm_rssi_monitor_h2c( void *p_dm_void, u8 macid ) { struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void; struct _rate_adaptive_table_ *p_ra_t = &p_dm->dm_ra_table; struct cmn_sta_info *p_sta = p_dm->p_phydm_sta_info[macid]; struct ra_sta_info *p_ra = NULL; u8 h2c_val[H2C_MAX_LENGTH] = {0}; u8 stbc_en, ldpc_en; u8 bf_en = 0; u8 is_rx, is_tx; if (is_sta_active(p_sta)) { p_ra = &(p_sta->ra_info); } else { PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("[Warning] %s invalid sta_info\n", __func__)); return; } PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("%s ======>\n", __func__)); PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("MACID=%d\n", p_sta->mac_id)); is_rx = (p_ra->txrx_state == RX_STATE) ? 1 : 0; is_tx = (p_ra->txrx_state == TX_STATE) ? 1 : 0; stbc_en = (p_sta->stbc_en) ? 1 : 0; ldpc_en = (p_sta->ldpc_en) ? 1 : 0; #ifdef CONFIG_BEAMFORMING if ((p_sta->bf_info.ht_beamform_cap & BEAMFORMING_HT_BEAMFORMEE_ENABLE) || (p_sta->bf_info.vht_beamform_cap & BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) { bf_en = 1; } #endif if (p_ra_t->RA_threshold_offset != 0) { PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("RA_th_ofst = (( %s%d ))\n", ((p_ra_t->RA_offset_direction) ? "+" : "-"), p_ra_t->RA_threshold_offset)); } h2c_val[0] = p_sta->mac_id; h2c_val[1] = 0; h2c_val[2] = p_sta->rssi_stat.rssi; h2c_val[3] = is_rx | (stbc_en << 1) | ((p_dm->noisy_decision & 0x1) << 2) | (bf_en << 6); h2c_val[4] = (p_ra_t->RA_threshold_offset & 0x7f) | ((p_ra_t->RA_offset_direction & 0x1) << 7); h2c_val[5] = 0; h2c_val[6] = 0; PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("PHYDM h2c[0x42]=0x%x %x %x %x %x %x %x\n", h2c_val[6], h2c_val[5], h2c_val[4], h2c_val[3], h2c_val[2], h2c_val[1], h2c_val[0])); #if (RTL8188E_SUPPORT == 1) if (p_dm->support_ic_type == ODM_RTL8188E) odm_ra_set_rssi_8188e(p_dm, (u8)(p_sta->mac_id & 0xFF), p_sta->rssi_stat.rssi & 0x7F); else #endif { odm_fill_h2c_cmd(p_dm, ODM_H2C_RSSI_REPORT, H2C_MAX_LENGTH, h2c_val); } } void phydm_calculate_rssi_min_max( void *p_dm_void ) { struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void; struct cmn_sta_info *p_sta; s8 rssi_max_tmp = 0, rssi_min_tmp = 100; u8 i; u8 sta_cnt = 0; if (!p_dm->is_linked) return; PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("%s ======>\n", __func__)); for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { p_sta = p_dm->p_phydm_sta_info[i]; if (is_sta_active(p_sta)) { sta_cnt++; if (p_sta->rssi_stat.rssi < rssi_min_tmp) rssi_min_tmp = p_sta->rssi_stat.rssi; if (p_sta->rssi_stat.rssi > rssi_max_tmp) rssi_max_tmp = p_sta->rssi_stat.rssi; /*[Send RSSI to FW]*/ if (p_sta->ra_info.disable_ra == false) phydm_rssi_monitor_h2c(p_dm, i); if (sta_cnt == p_dm->number_linked_client) break; } } p_dm->rssi_max = (u8)rssi_max_tmp; p_dm->rssi_min = (u8)rssi_min_tmp; } #endif #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) s32 phydm_find_minimum_rssi( struct PHY_DM_STRUCT *p_dm, struct _ADAPTER *p_adapter, boolean *p_is_link_temp ) { HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); PMGNT_INFO p_mgnt_info = &(p_adapter->MgntInfo); boolean act_as_ap = ACTING_AS_AP(p_adapter); /* 1.Determine the minimum RSSI */ if ((!p_mgnt_info->bMediaConnect) || (act_as_ap && (p_hal_data->EntryMinUndecoratedSmoothedPWDB == 0))) {/* We should check AP mode and Entry info.into consideration, revised by Roger, 2013.10.18*/ p_hal_data->MinUndecoratedPWDBForDM = 0; *p_is_link_temp = false; } else *p_is_link_temp = true; if (p_mgnt_info->bMediaConnect) { /* Default port*/ if (act_as_ap || p_mgnt_info->mIbss) { p_hal_data->MinUndecoratedPWDBForDM = p_hal_data->EntryMinUndecoratedSmoothedPWDB; /**/ } else { p_hal_data->MinUndecoratedPWDBForDM = p_hal_data->UndecoratedSmoothedPWDB; /**/ } } else { /* associated entry pwdb*/ p_hal_data->MinUndecoratedPWDBForDM = p_hal_data->EntryMinUndecoratedSmoothedPWDB; /**/ } return p_hal_data->MinUndecoratedPWDBForDM; } void odm_rssi_monitor_check_mp( void *p_dm_void ) { struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void; struct _rate_adaptive_table_ *p_ra_table = &p_dm->dm_ra_table; u8 h2c_parameter[H2C_0X42_LENGTH] = {0}; u32 i; boolean is_ext_ra_info = true; u8 cmdlen = H2C_0X42_LENGTH; u8 tx_bf_en = 0, stbc_en = 0; struct _ADAPTER *adapter = p_dm->adapter; HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(adapter); struct sta_info *p_entry = NULL; s32 tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff; PMGNT_INFO p_mgnt_info = &adapter->MgntInfo; PMGNT_INFO p_default_mgnt_info = &adapter->MgntInfo; u64 cur_tx_ok_cnt = 0, cur_rx_ok_cnt = 0; #if (BEAMFORMING_SUPPORT == 1) #ifndef BEAMFORMING_VERSION_1 enum beamforming_cap beamform_cap = BEAMFORMING_CAP_NONE; #endif #endif struct _ADAPTER *p_loop_adapter = GetDefaultAdapter(adapter); if (p_dm->support_ic_type == ODM_RTL8188E) { is_ext_ra_info = false; cmdlen = 3; } while (p_loop_adapter) { if (p_loop_adapter != NULL) { p_mgnt_info = &p_loop_adapter->MgntInfo; cur_tx_ok_cnt = p_loop_adapter->TxStats.NumTxBytesUnicast - p_mgnt_info->lastTxOkCnt; cur_rx_ok_cnt = p_loop_adapter->RxStats.NumRxBytesUnicast - p_mgnt_info->lastRxOkCnt; p_mgnt_info->lastTxOkCnt = cur_tx_ok_cnt; p_mgnt_info->lastRxOkCnt = cur_rx_ok_cnt; } for (i = 0; i < ASSOCIATE_ENTRY_NUM; i++) { if (IsAPModeExist(p_loop_adapter)) { if (GetFirstExtAdapter(p_loop_adapter) != NULL && GetFirstExtAdapter(p_loop_adapter) == p_loop_adapter) p_entry = AsocEntry_EnumStation(p_loop_adapter, i); else if (GetFirstGOPort(p_loop_adapter) != NULL && IsFirstGoAdapter(p_loop_adapter)) p_entry = AsocEntry_EnumStation(p_loop_adapter, i); } else { if (GetDefaultAdapter(p_loop_adapter) == p_loop_adapter) p_entry = AsocEntry_EnumStation(p_loop_adapter, i); } if (p_entry != NULL) { if (p_entry->bAssociated) { RT_DISP_ADDR(FDM, DM_PWDB, ("p_entry->mac_addr ="), GET_STA_INFO(p_entry).mac_addr); RT_DISP(FDM, DM_PWDB, ("p_entry->rssi = 0x%x(%d)\n", GET_STA_INFO(p_entry).rssi_stat.rssi, GET_STA_INFO(p_entry).rssi_stat.rssi)); /* 2 BF_en */ #if (BEAMFORMING_SUPPORT == 1) #ifndef BEAMFORMING_VERSION_1 beamform_cap = phydm_beamforming_get_entry_beam_cap_by_mac_id(p_dm, GET_STA_INFO(p_entry).mac_id); if (beamform_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) tx_bf_en = 1; #else if (Beamform_GetSupportBeamformerCap(GetDefaultAdapter(adapter), p_entry)) tx_bf_en = 1; #endif #endif /* 2 STBC_en */ if ((IS_WIRELESS_MODE_AC(adapter) && TEST_FLAG(p_entry->VHTInfo.STBC, STBC_VHT_ENABLE_TX)) || TEST_FLAG(p_entry->HTInfo.STBC, STBC_HT_ENABLE_TX)) stbc_en = 1; if (GET_STA_INFO(p_entry).rssi_stat.rssi < tmp_entry_min_pwdb) tmp_entry_min_pwdb = GET_STA_INFO(p_entry).rssi_stat.rssi; if (GET_STA_INFO(p_entry).rssi_stat.rssi > tmp_entry_max_pwdb) tmp_entry_max_pwdb = GET_STA_INFO(p_entry).rssi_stat.rssi; h2c_parameter[4] = (p_ra_table->RA_threshold_offset & 0x7f) | (p_ra_table->RA_offset_direction << 7); PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("RA_threshold_offset = (( %s%d ))\n", ((p_ra_table->RA_threshold_offset == 0) ? " " : ((p_ra_table->RA_offset_direction) ? "+" : "-")), p_ra_table->RA_threshold_offset)); if (is_ext_ra_info) { if (cur_rx_ok_cnt > (cur_tx_ok_cnt * 6)) h2c_parameter[3] |= RAINFO_BE_RX_STATE; if (tx_bf_en) h2c_parameter[3] |= RAINFO_BF_STATE; else { if (stbc_en) h2c_parameter[3] |= RAINFO_STBC_STATE; } if (p_dm->noisy_decision) h2c_parameter[3] |= RAINFO_NOISY_STATE; else h2c_parameter[3] &= (~RAINFO_NOISY_STATE); if (p_dm->h2c_rarpt_connect) { h2c_parameter[3] |= RAINFO_INIT_RSSI_RATE_STATE; PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("h2c_rarpt_connect = (( %d ))\n", p_dm->h2c_rarpt_connect)); } } h2c_parameter[2] = (u8)(GET_STA_INFO(p_entry).rssi_stat.rssi & 0xFF); /* h2c_parameter[1] = 0x20;*/ /* fw v12 cmdid 5:use max macid ,for nic ,default macid is 0 ,max macid is 1 */ h2c_parameter[0] = (GET_STA_INFO(p_entry).mac_id); odm_fill_h2c_cmd(p_dm, ODM_H2C_RSSI_REPORT, cmdlen, h2c_parameter); } } else break; } p_loop_adapter = GetNextExtAdapter(p_loop_adapter); } /*Default port*/ if (tmp_entry_max_pwdb != 0) { /* If associated entry is found */ p_hal_data->EntryMaxUndecoratedSmoothedPWDB = tmp_entry_max_pwdb; RT_DISP(FDM, DM_PWDB, ("EntryMaxPWDB = 0x%x(%d)\n", tmp_entry_max_pwdb, tmp_entry_max_pwdb)); } else p_hal_data->EntryMaxUndecoratedSmoothedPWDB = 0; if (tmp_entry_min_pwdb != 0xff) { /* If associated entry is found */ p_hal_data->EntryMinUndecoratedSmoothedPWDB = tmp_entry_min_pwdb; RT_DISP(FDM, DM_PWDB, ("EntryMinPWDB = 0x%x(%d)\n", tmp_entry_min_pwdb, tmp_entry_min_pwdb)); } else p_hal_data->EntryMinUndecoratedSmoothedPWDB = 0; /* Default porti sent RSSI to FW */ if (p_hal_data->bUseRAMask) { PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("1 RA First Link, RSSI[%d] = ((%d)) , ra_rpt_linked = ((%d))\n", WIN_DEFAULT_PORT_MACID, p_hal_data->UndecoratedSmoothedPWDB, p_hal_data->ra_rpt_linked)); if (p_hal_data->UndecoratedSmoothedPWDB > 0) { PRT_HIGH_THROUGHPUT p_ht_info = GET_HT_INFO(p_default_mgnt_info); PRT_VERY_HIGH_THROUGHPUT p_vht_info = GET_VHT_INFO(p_default_mgnt_info); /* BF_en*/ #if (BEAMFORMING_SUPPORT == 1) #ifndef BEAMFORMING_VERSION_1 beamform_cap = phydm_beamforming_get_entry_beam_cap_by_mac_id(p_dm, p_default_mgnt_info->m_mac_id); if (beamform_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) tx_bf_en = 1; #else if (Beamform_GetSupportBeamformerCap(GetDefaultAdapter(adapter), NULL)) tx_bf_en = 1; #endif #endif /* STBC_en*/ if ((IS_WIRELESS_MODE_AC(adapter) && TEST_FLAG(p_vht_info->VhtCurStbc, STBC_VHT_ENABLE_TX)) || TEST_FLAG(p_ht_info->HtCurStbc, STBC_HT_ENABLE_TX)) stbc_en = 1; h2c_parameter[4] = (p_ra_table->RA_threshold_offset & 0x7f) | (p_ra_table->RA_offset_direction << 7); PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("RA_threshold_offset = (( %s%d ))\n", ((p_ra_table->RA_threshold_offset == 0) ? " " : ((p_ra_table->RA_offset_direction) ? "+" : "-")), p_ra_table->RA_threshold_offset)); if (is_ext_ra_info) { if (tx_bf_en) h2c_parameter[3] |= RAINFO_BF_STATE; else { if (stbc_en) h2c_parameter[3] |= RAINFO_STBC_STATE; } if (p_dm->h2c_rarpt_connect) { h2c_parameter[3] |= RAINFO_INIT_RSSI_RATE_STATE; PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("h2c_rarpt_connect = (( %d ))\n", p_dm->h2c_rarpt_connect)); } if (p_dm->noisy_decision == 1) { h2c_parameter[3] |= RAINFO_NOISY_STATE; PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("[RSSIMonitorCheckMP] Send H2C to FW\n")); } else h2c_parameter[3] &= (~RAINFO_NOISY_STATE); PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("[RSSIMonitorCheckMP] h2c_parameter=%x\n", h2c_parameter[3])); } h2c_parameter[2] = (u8)(p_hal_data->UndecoratedSmoothedPWDB & 0xFF); /*h2c_parameter[1] = 0x20;*/ /* fw v12 cmdid 5:use max macid ,for nic ,default macid is 0 ,max macid is 1*/ h2c_parameter[0] = WIN_DEFAULT_PORT_MACID; /* fw v12 cmdid 5:use max macid ,for nic ,default macid is 0 ,max macid is 1*/ odm_fill_h2c_cmd(p_dm, ODM_H2C_RSSI_REPORT, cmdlen, h2c_parameter); } } else PlatformEFIOWrite1Byte(adapter, 0x4fe, (u8)p_hal_data->UndecoratedSmoothedPWDB); { struct _ADAPTER *p_loop_adapter = GetDefaultAdapter(adapter); boolean default_pointer_value, *p_is_link_temp = &default_pointer_value; s32 global_rssi_min = 0xFF, local_rssi_min; boolean is_link = false; while (p_loop_adapter) { local_rssi_min = phydm_find_minimum_rssi(p_dm, p_loop_adapter, p_is_link_temp); /* dbg_print("p_hal_data->is_linked=%d, local_rssi_min=%d\n", p_hal_data->is_linked, local_rssi_min); */ if (*p_is_link_temp) is_link = true; if ((local_rssi_min < global_rssi_min) && (*p_is_link_temp)) global_rssi_min = local_rssi_min; p_loop_adapter = GetNextExtAdapter(p_loop_adapter); } p_hal_data->bLinked = is_link; p_dm->is_linked = is_link; p_dm->rssi_min = (u8)((is_link) ? global_rssi_min : 0); } } #endif void phydm_rssi_monitor_check( void *p_dm_void ) { struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void; if (!(p_dm->support_ability & ODM_BB_RSSI_MONITOR)) return; if ((p_dm->phydm_sys_up_time % 2) == 1) /*for AP watchdog period = 1 sec*/ return; PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("%s ======>\n", __func__)); #ifdef PHYDM_3RD_REFORM_RSSI_MONOTOR phydm_calculate_rssi_min_max(p_dm); #else #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) odm_rssi_monitor_check_mp(p_dm); #endif #endif PHYDM_DBG(p_dm, DBG_RSSI_MNTR, ("RSSI {max, min} = {%d, %d}\n", p_dm->rssi_max, p_dm->rssi_min)); } void phydm_rssi_monitor_init( void *p_dm_void ) { struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void; struct _rate_adaptive_table_ *p_ra_table = &p_dm->dm_ra_table; #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) struct _ADAPTER *adapter = p_dm->adapter; HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(adapter); p_ra_table->PT_collision_pre = true; /*used in odm_dynamic_arfb_select(WIN only)*/ p_hal_data->UndecoratedSmoothedPWDB = -1; p_hal_data->ra_rpt_linked = false; #endif p_ra_table->firstconnect = false; p_dm->rssi_max = 0; p_dm->rssi_min = 0; } #endif