ps.c revision 7ea4724036ed17ec811cb8082af7760f04484ef7
10c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/****************************************************************************** 20c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 30c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Copyright(c) 2009-2010 Realtek Corporation. 40c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 50c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * This program is free software; you can redistribute it and/or modify it 60c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * under the terms of version 2 of the GNU General Public License as 70c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * published by the Free Software Foundation. 80c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 90c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * This program is distributed in the hope that it will be useful, but WITHOUT 100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * more details. 130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * You should have received a copy of the GNU General Public License along with 150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * this program; if not, write to the Free Software Foundation, Inc., 160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * The full GNU General Public License is included in this distribution in the 190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * file called LICENSE. 200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Contact Information: 220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * wlanfae <wlanfae@realtek.com> 230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, 240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Hsinchu 300, Taiwan. 250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Larry Finger <Larry.Finger@lwfinger.net> 270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *****************************************************************************/ 290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "wifi.h" 310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "base.h" 320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "ps.h" 330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_enable_nic(struct ieee80211_hw *hw) 350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger bool init_status = true; 400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<1> reset trx ring */ 420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlhal->interface == INTF_PCI) 430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->reset_trx_ring(hw); 440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (is_hal_stop(rtlhal)) 460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Driver is already down!\n")); 480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Enable Adapter */ 500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->hw_init(hw); 510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); 520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*init_status = false; */ 530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<3> Enable Interrupt */ 550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->enable_interrupt(hw); 560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<enable timer> */ 580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_watch_dog_timer_callback((unsigned long)hw); 590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return init_status; 610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_enable_nic); 630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_disable_nic(struct ieee80211_hw *hw) 650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger bool status = true; 670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<1> Stop all timer */ 700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_deinit_deferred_work(hw); 710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Disable Interrupt */ 730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->disable_interrupt(hw); 740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<3> Disable Adapter */ 760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->hw_disable(hw); 770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return status; 790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_disable_nic); 810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_set_rf_state(struct ieee80211_hw *hw, 830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate state_toset, 840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u32 changesource, bool protect_or_not) 850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 897ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger bool actionallowed = false; 900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u16 rfwait_cnt = 0; 910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger unsigned long flag; 920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*protect_or_not = true; */ 940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (protect_or_not) 960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger goto no_protect; 970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Only one thread can change 1000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *the RF state at one time, and others 1010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *should wait to be executed. 1020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 1030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger while (true) { 1040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); 1050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->rfchange_inprogress) { 1060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, 1070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger flag); 1080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 1100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("RF Change in progress!" 1110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger "Wait to set..state_toset(%d).\n", 1120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger state_toset)); 1130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Set RF after the previous action is done. */ 1150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger while (ppsc->rfchange_inprogress) { 1160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rfwait_cnt++; 1170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger mdelay(1); 1180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 1200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Wait too long, return false to avoid 1210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *to be stuck here. 1220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 1230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rfwait_cnt > 100) 1240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 1250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 1270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfchange_inprogress = true; 1280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, 1290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger flag); 1300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerno_protect: 1350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 1360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger switch (state_toset) { 1380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFON: 1390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason &= (~changesource); 1400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((changesource == RF_CHANGE_BY_HW) && 1427ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger (ppsc->hwradiooff == true)) { 1437ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = false; 1440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (!ppsc->rfoff_reason) { 1470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason = 0; 1487ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFOFF: 1540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((changesource == RF_CHANGE_BY_HW) 1567ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger && (ppsc->hwradiooff == false)) { 1577ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = true; 1580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1617ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFSLEEP: 1650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1667ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger default: 1700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, 1710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("switch case not process\n")); 1720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1757ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (actionallowed) 1760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); 1770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (!protect_or_not) { 1790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); 1800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfchange_inprogress = false; 1810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); 1820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1847ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger return actionallowed; 1850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 1860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_set_rf_state); 1870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) 1890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 1900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 1910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 1920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 1930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1947ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = true; 1950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { 1970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && 1980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) && 1990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 2000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 2010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); 2020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, 2060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RF_CHANGE_BY_IPS, false); 2070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->inactive_pwrstate == ERFOFF && 2090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 2100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { 2110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->enable_aspm(hw); 2120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); 2130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2167ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = false; 2170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off_wq_callback(void *data) 2200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_works *rtlworks = 2220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq); 2230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct ieee80211_hw *hw = rtlworks->hw; 2240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 2260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 2270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 2290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode != NL80211_IFTYPE_STATION) { 2310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 2320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("not station return\n")); 2330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (is_hal_stop(rtlhal)) 2370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 2400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2427ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 2430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 2440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 2460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Do not enter IPS in the following conditions: 2470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(1) RF is already OFF or Sleep 2487ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger *(2) swrf_processing (indicates the IPS is still under going) 2490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(3) Connectted (only disconnected can trigger IPS) 2500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(4) IBSS (send Beacon) 2510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(5) AP mode (send Beacon) 2520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(6) monitor mode (rcv packet) 2530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate == ERFON && 2567ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 2570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (mac->link_state == MAC80211_NOLINK) && 2580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger !mac->act_scanning) { 2590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, 2600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("IPSEnter(): Turn off RF.\n")); 2610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFOFF; 2637ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = true; 2640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*rtl_pci_reset_trx_ring(hw); */ 2660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 2670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off(struct ieee80211_hw *hw) 2720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 2760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *because when link with ap, mac80211 will ask us 2770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *to disable nic quickly after scan before linking, 2780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *this will cause link failed, so we delay 100ms here 2790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger queue_delayed_work(rtlpriv->works.rtl_wq, 2810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger &rtlpriv->works.ips_nic_off_wq, MSECS(100)); 2820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_on(struct ieee80211_hw *hw) 2850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 289d704300fa546a613ec3821b908528b20685cb92aLarry Finger unsigned long flags; 2900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 291d704300fa546a613ec3821b908528b20685cb92aLarry Finger spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); 2920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2937ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 2940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 2950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate != ERFON && 2977ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 2980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { 2990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFON; 3017ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = false; 3020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 3040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 307d704300fa546a613ec3821b908528b20685cb92aLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags); 3080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*for FW LPS*/ 3110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* 3130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Determine if we can set Fw into PS mode 3140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *in current condition.Return TRUE if it 3150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *can enter PS mode. 3160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 3170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic bool rtl_get_fwlps_doze(struct ieee80211_hw *hw) 3180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 3220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u32 ps_timediff; 3230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ps_timediff = jiffies_to_msecs(jiffies - 3250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->last_delaylps_stamp_jiffies); 3260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ps_timediff < 2000) { 3280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 3290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Delay enter Fw LPS for DHCP, ARP," 3300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger " or EAPOL exchanging state.\n")); 3310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return true; 3410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* Change current and default preamble mode.*/ 3440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) 3450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 3490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u8 rpwm_val, fw_pwrmode; 3500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == rt_psmode) 3580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Update power save mode configured. */ 3610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = rt_psmode; 3620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 3640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *<FW control LPS> 3650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *1. Enter PS mode 3660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode 3670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * cmd to set Fw into PS mode. 3680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *2. Leave PS mode 3690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Send H2C fw_pwrmode cmd to Fw to set Fw into Active 3700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * mode and set RPWM to turn RF on. 3710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 3720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3737ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) && 3740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->report_linked) { 3757ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger bool fw_current_inps; 3760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == EACTIVE) { 3770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 3780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("FW LPS leave ps_mode:%x\n", 3790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger FW_PS_ACTIVE_MODE)); 3800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rpwm_val = 0x0C; /* RF on */ 3820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger fw_pwrmode = FW_PS_ACTIVE_MODE; 3830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, 3840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&rpwm_val)); 3850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 3860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_H2C_FW_PWRMODE, 3870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&fw_pwrmode)); 3887ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger fw_current_inps = false; 3890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 3910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_FW_PSMODE_STATUS, 3927ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger (u8 *) (&fw_current_inps)); 3930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 3950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtl_get_fwlps_doze(hw)) { 3960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 3970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("FW LPS enter ps_mode:%x\n", 3980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->fwctrl_psmode)); 3990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rpwm_val = 0x02; /* RF off */ 4017ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger fw_current_inps = true; 4020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 4030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_FW_PSMODE_STATUS, 4047ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger (u8 *) (&fw_current_inps)); 4050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 4060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_H2C_FW_PWRMODE, 4070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&ppsc->fwctrl_psmode)); 4080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 4100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_SET_RPWM, 4110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&rpwm_val)); 4120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 4130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Reset the power save related parameters. */ 4140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = EACTIVE; 4150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 4190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Enter the leisure power save mode.*/ 4210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_enter(struct ieee80211_hw *hw) 4220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 4230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 4240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 4250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 4260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger unsigned long flag; 4270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4287ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (!(ppsc->fwctrl_lps && ppsc->leisure_ps)) 4290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 4320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4347ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (rtlpriv->link_info.busytraffic) 4350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ 4380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->cnt_after_linked < 5) 4390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 4420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 4450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 4480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4497ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->leisure_ps) { 4500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Idle for a while if we connect to AP a while ago. */ 4510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->cnt_after_linked >= 2) { 4520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == EACTIVE) { 4530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 4540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Enter 802.11 power save mode...\n")); 4550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_lps_set_psmode(hw, EAUTOPS); 4570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 4610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 4620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Leave the leisure power save mode.*/ 4640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_leave(struct ieee80211_hw *hw) 4650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 4660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 4670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 4680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 4690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger unsigned long flag; 4700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 4720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4737ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->fwctrl_lps && ppsc->leisure_ps) { 4740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode != EACTIVE) { 4750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*FIX ME */ 4770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->enable_interrupt(hw); 4780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && 4800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) && 4810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 4820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 4830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM); 4840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 4870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Busy Traffic,Leave 802.11 power save..\n")); 4880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_lps_set_psmode(hw, EACTIVE); 4900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 4930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 494