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