ps.c revision 099fb8ab1e57e5d609ac686cc0ab6d1835a79155
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 400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<1> reset trx ring */ 410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlhal->interface == INTF_PCI) 420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->reset_trx_ring(hw); 430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (is_hal_stop(rtlhal)) 450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Driver is already down!\n")); 470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Enable Adapter */ 490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->hw_init(hw); 500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); 510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<3> Enable Interrupt */ 530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->enable_interrupt(hw); 540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<enable timer> */ 560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_watch_dog_timer_callback((unsigned long)hw); 570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 58cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return true; 590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_enable_nic); 610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_disable_nic(struct ieee80211_hw *hw) 630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<1> Stop all timer */ 670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_deinit_deferred_work(hw); 680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Disable Interrupt */ 700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->disable_interrupt(hw); 710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<3> Disable Adapter */ 730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->hw_disable(hw); 740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 75324732848c42bf79988479ee1b4359e15f08154bLarry Finger return true; 760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_disable_nic); 780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_set_rf_state(struct ieee80211_hw *hw, 800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate state_toset, 810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u32 changesource, bool protect_or_not) 820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 867ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger bool actionallowed = false; 870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u16 rfwait_cnt = 0; 880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger unsigned long flag; 890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*protect_or_not = true; */ 910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (protect_or_not) 930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger goto no_protect; 940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Only one thread can change 970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *the RF state at one time, and others 980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *should wait to be executed. 990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 1000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger while (true) { 1010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); 1020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->rfchange_inprogress) { 1030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, 1040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger flag); 1050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 1070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("RF Change in progress!" 1080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger "Wait to set..state_toset(%d).\n", 1090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger state_toset)); 1100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Set RF after the previous action is done. */ 1120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger while (ppsc->rfchange_inprogress) { 1130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rfwait_cnt++; 1140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger mdelay(1); 1150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 1170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Wait too long, return false to avoid 1180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *to be stuck here. 1190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 1200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rfwait_cnt > 100) 1210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 1220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 1240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfchange_inprogress = true; 1250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, 1260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger flag); 1270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerno_protect: 1320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 1330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger switch (state_toset) { 1350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFON: 1360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason &= (~changesource); 1370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((changesource == RF_CHANGE_BY_HW) && 1397ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger (ppsc->hwradiooff == true)) { 1407ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = false; 1410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (!ppsc->rfoff_reason) { 1440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason = 0; 1457ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFOFF: 1510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((changesource == RF_CHANGE_BY_HW) 1537ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger && (ppsc->hwradiooff == false)) { 1547ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = true; 1550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1587ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFSLEEP: 1620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1637ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger default: 1670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, 1680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("switch case not process\n")); 1690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1727ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (actionallowed) 1730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); 1740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (!protect_or_not) { 1760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); 1770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfchange_inprogress = false; 1780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); 1790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1817ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger return actionallowed; 1820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 1830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_set_rf_state); 1840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) 1860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 1870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 1880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 1890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 1900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1917ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = true; 1920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 193099fb8ab1e57e5d609ac686cc0ab6d1835a79155Larry Finger if (ppsc->inactive_pwrstate == ERFON && 194cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlhal->interface == INTF_PCI) { 1950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && 196cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && 1970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 1980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 199cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 2000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, 2040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RF_CHANGE_BY_IPS, false); 2050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->inactive_pwrstate == ERFOFF && 2070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 208cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && 209cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 2100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->enable_aspm(hw); 211cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 2120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2157ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = false; 2160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off_wq_callback(void *data) 2190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_works *rtlworks = 2210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq); 2220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct ieee80211_hw *hw = rtlworks->hw; 2230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 2250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 2260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 2280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode != NL80211_IFTYPE_STATION) { 2300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 2310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("not station return\n")); 2320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 235cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->link_state > MAC80211_NOLINK) 236cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 237cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 2380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (is_hal_stop(rtlhal)) 2390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 2420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2447ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 2450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 2460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 2480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Do not enter IPS in the following conditions: 2490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(1) RF is already OFF or Sleep 2507ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger *(2) swrf_processing (indicates the IPS is still under going) 2510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(3) Connectted (only disconnected can trigger IPS) 2520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(4) IBSS (send Beacon) 2530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(5) AP mode (send Beacon) 2540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(6) monitor mode (rcv packet) 2550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate == ERFON && 2587ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 2590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (mac->link_state == MAC80211_NOLINK) && 2600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger !mac->act_scanning) { 2610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, 2620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("IPSEnter(): Turn off RF.\n")); 2630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFOFF; 2657ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = true; 2660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*rtl_pci_reset_trx_ring(hw); */ 2680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 2690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off(struct ieee80211_hw *hw) 2740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 2780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *because when link with ap, mac80211 will ask us 2790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *to disable nic quickly after scan before linking, 2800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *this will cause link failed, so we delay 100ms here 2810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger queue_delayed_work(rtlpriv->works.rtl_wq, 2830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger &rtlpriv->works.ips_nic_off_wq, MSECS(100)); 2840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_on(struct ieee80211_hw *hw) 2870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 289cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 2900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 292d704300fa546a613ec3821b908528b20685cb92aLarry Finger unsigned long flags; 2930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 294cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->opmode != NL80211_IFTYPE_STATION) 295cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 296cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 297d704300fa546a613ec3821b908528b20685cb92aLarry Finger spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); 2980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2997ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 3000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 3010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate != ERFON && 3037ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 3040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { 3050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFON; 3077ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = false; 3080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 3100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 313d704300fa546a613ec3821b908528b20685cb92aLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags); 3140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*for FW LPS*/ 3170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* 3190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Determine if we can set Fw into PS mode 3200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *in current condition.Return TRUE if it 3210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *can enter PS mode. 3220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 3230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic bool rtl_get_fwlps_doze(struct ieee80211_hw *hw) 3240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 3280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u32 ps_timediff; 3290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ps_timediff = jiffies_to_msecs(jiffies - 3310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->last_delaylps_stamp_jiffies); 3320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ps_timediff < 2000) { 3340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 3350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Delay enter Fw LPS for DHCP, ARP," 3360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger " or EAPOL exchanging state.\n")); 3370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return true; 3470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* Change current and default preamble mode.*/ 3500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) 3510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 3550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u8 rpwm_val, fw_pwrmode; 3560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == rt_psmode) 3640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Update power save mode configured. */ 3670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = rt_psmode; 3680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 3700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *<FW control LPS> 3710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *1. Enter PS mode 3720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode 3730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * cmd to set Fw into PS mode. 3740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *2. Leave PS mode 3750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Send H2C fw_pwrmode cmd to Fw to set Fw into Active 3760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * mode and set RPWM to turn RF on. 3770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 3780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 379cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((ppsc->fwctrl_lps) && ppsc->report_linked) { 3807ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger bool fw_current_inps; 3810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == EACTIVE) { 3820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 3830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("FW LPS leave ps_mode:%x\n", 3840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger FW_PS_ACTIVE_MODE)); 3850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rpwm_val = 0x0C; /* RF on */ 3870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger fw_pwrmode = FW_PS_ACTIVE_MODE; 3880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, 3890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&rpwm_val)); 3900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 3910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_H2C_FW_PWRMODE, 3920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&fw_pwrmode)); 3937ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger fw_current_inps = false; 3940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 3960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_FW_PSMODE_STATUS, 3977ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger (u8 *) (&fw_current_inps)); 3980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 4000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtl_get_fwlps_doze(hw)) { 4010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 4020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("FW LPS enter ps_mode:%x\n", 4030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->fwctrl_psmode)); 4040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rpwm_val = 0x02; /* RF off */ 4067ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger fw_current_inps = true; 4070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 4080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_FW_PSMODE_STATUS, 4097ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger (u8 *) (&fw_current_inps)); 4100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 4110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_H2C_FW_PWRMODE, 4120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&ppsc->fwctrl_psmode)); 4130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 4150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger HW_VAR_SET_RPWM, 4160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (u8 *) (&rpwm_val)); 4170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 4180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Reset the power save related parameters. */ 4190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = EACTIVE; 4200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 4240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Enter the leisure power save mode.*/ 4260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_enter(struct ieee80211_hw *hw) 4270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 4280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 4290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 4300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 4310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger unsigned long flag; 4320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 433cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!ppsc->fwctrl_lps) 4340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 4370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4397ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (rtlpriv->link_info.busytraffic) 4400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ 4430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->cnt_after_linked < 5) 4440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 4470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 4500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 4530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 454cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* Idle for a while if we connect to AP a while ago. */ 455cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->cnt_after_linked >= 2) { 456cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->dot11_psmode == EACTIVE) { 457cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 4580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Enter 802.11 power save mode...\n")); 4590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 460cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_lps_set_psmode(hw, EAUTOPS); 4610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 463cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 4640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 4650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 4660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Leave the leisure power save mode.*/ 4680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_leave(struct ieee80211_hw *hw) 4690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 4700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 4710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 4720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 4730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger unsigned long flag; 4740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 4760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 477cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->fwctrl_lps) { 4780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode != EACTIVE) { 4790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*FIX ME */ 4810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->enable_interrupt(hw); 4820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && 484cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && 4850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 4860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 487cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 4880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 4910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ("Busy Traffic,Leave 802.11 power save..\n")); 4920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_lps_set_psmode(hw, EACTIVE); 4940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 4970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 498cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 499cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li/* For sw LPS*/ 500cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) 501cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 502cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 503cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 504cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_hdr *hdr = (void *) data; 505cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_tim_ie *tim_ie; 506cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 *tim; 507cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 tim_len; 508cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool u_buffed; 509cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool m_buffed; 510cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 511cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->opmode != NL80211_IFTYPE_STATION) 512cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 513cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 514cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.swctrl_lps) 515cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 516cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 517cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->mac80211.link_state != MAC80211_LINKED) 518cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 519cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 520cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.sw_ps_enabled) 521cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 522cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 523cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.fwctrl_lps) 524cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 525cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 526cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) 527cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 528cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 529cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* check if this really is a beacon */ 530cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!ieee80211_is_beacon(hdr->frame_control)) 531cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 532cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 533cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* min. beacon length + FCS_LEN */ 534cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (len <= 40 + FCS_LEN) 535cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 536cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 537cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* and only beacons from the associated BSSID, please */ 538cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) 539cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 540cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 541cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_beacon = jiffies; 542cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 543cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); 544cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!tim) 545cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 546cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 547cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (tim[1] < sizeof(*tim_ie)) 548cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 549cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 550cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim_len = tim[1]; 551cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim_ie = (struct ieee80211_tim_ie *) &tim[2]; 552cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 553cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) 554cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.dtim_counter = tim_ie->dtim_count; 555cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 556cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* Check whenever the PHY can be turned off again. */ 557cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 558cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* 1. What about buffered unicast traffic for our AID? */ 559cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u_buffed = ieee80211_check_tim(tim_ie, tim_len, 560cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->mac80211.assoc_id); 561cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 562cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* 2. Maybe the AP wants to send multicast/broadcast data? */ 563cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li m_buffed = tim_ie->bitmap_ctrl & 0x01; 564cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.multi_buffered = m_buffed; 565cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 566cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* unicast will process by mac80211 through 567cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * set ~IEEE80211_CONF_PS, So we just check 568cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * multicast frames here */ 569cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!m_buffed) { 570cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* back to low-power land. and delay is 571cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * prevent null power save frame tx fail */ 572cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li queue_delayed_work(rtlpriv->works.rtl_wq, 573cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li &rtlpriv->works.ps_work, MSECS(5)); 574cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } else { 575cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, " 576cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li "m_buffered: %x\n", u_buffed, m_buffed)); 577cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 578cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 579cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 580cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rf_awake(struct ieee80211_hw *hw) 581cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 582cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 583cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 584cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 585cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li unsigned long flag; 586cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 587cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.swctrl_lps) 588cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 589cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->link_state != MAC80211_LINKED) 590cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 591cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 592cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && 593cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 594cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->intf_ops->disable_aspm(hw); 595cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 596cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 597cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 598cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 599cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); 600cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 601cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 602cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 603cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rfon_wq_callback(void *data) 604cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 605cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works *rtlworks = 606cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); 607cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_hw *hw = rtlworks->hw; 608cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 609cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_swlps_rf_awake(hw); 610cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 611cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 612cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rf_sleep(struct ieee80211_hw *hw) 613cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 614cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 615cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 616cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 617cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li unsigned long flag; 618cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 sleep_intv; 619cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 620cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.sw_ps_enabled) 621cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 622cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 623cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((rtlpriv->sec.being_setkey) || 624cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li (mac->opmode == NL80211_IFTYPE_ADHOC)) 625cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 626cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 627cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ 628cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) 629cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 630cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 631cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->link_info.busytraffic) 632cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 633cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 634cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); 635cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.rfchange_inprogress) { 636cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); 637cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 638cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 639cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); 640cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 641cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 642cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false); 643cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 644cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 645cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && 646cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 647cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->intf_ops->enable_aspm(hw); 648cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 649cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 650cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 651cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* here is power save alg, when this beacon is DTIM 652cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * we will set sleep time to dtim_period * n; 653cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * when this beacon is not DTIM, we will set sleep 654cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * time to sleep_intv = rtlpriv->psc.dtim_counter or 655cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ 656cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 657cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.dtim_counter == 0) { 658cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (hw->conf.ps_dtim_period == 1) 659cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = hw->conf.ps_dtim_period * 2; 660cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li else 661cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = hw->conf.ps_dtim_period; 662cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } else { 663cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = rtlpriv->psc.dtim_counter; 664cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 665cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 666cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) 667cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = MAX_SW_LPS_SLEEP_INTV; 668cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 669cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* this print should always be dtim_conter = 0 & 670cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * sleep = dtim_period, that meaons, we should 671cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * awake before every dtim */ 672cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, 673cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li ("dtim_counter:%x will sleep :%d" 674cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv)); 675cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 676cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* we tested that 40ms is enough for sw & hw sw delay */ 677cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, 678cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); 679cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 680cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 681cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 682cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_wq_callback(void *data) 683cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 684cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works *rtlworks = container_of_dwork_rtl(data, 685cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works, 686cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li ps_work); 687cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_hw *hw = rtlworks->hw; 688cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 689cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool ps = false; 690cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 691cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li ps = (hw->conf.flags & IEEE80211_CONF_PS); 692cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 693cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* we can sleep after ps null send ok */ 694cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.state_inap) { 695cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_swlps_rf_sleep(hw); 696cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 697cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.state && !ps) { 698cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - 699cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_action); 700cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 701cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 702cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ps) 703cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_slept = jiffies; 704cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 705cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_action = jiffies; 706cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.state = ps; 707cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 708cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 709