ps.c revision 2e8c5e56b307271c2dab6f8bfd1d8a3822ca2390
10c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/****************************************************************************** 20c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 3a8d760668eebc98915383481cb3d9eaf74c2a615Larry Finger * Copyright(c) 2009-2012 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 30ee40fa0656a730491765545ff7550f3c1ceb0fbcPaul Gortmaker#include <linux/export.h> 310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "wifi.h" 320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "base.h" 330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "ps.h" 340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_enable_nic(struct ieee80211_hw *hw) 360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 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, 47f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Driver is already down!\n"); 480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Enable Adapter */ 50b0302aba812bcc39291cdab9ad7e37008f352a91Larry Finger if (rtlpriv->cfg->ops->hw_init(hw)) 512e8c5e56b307271c2dab6f8bfd1d8a3822ca2390Olivier Langlois return false; 520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); 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 60cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return true; 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 struct rtl_priv *rtlpriv = rtl_priv(hw); 670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<1> Stop all timer */ 690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_deinit_deferred_work(hw); 700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Disable Interrupt */ 720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->disable_interrupt(hw); 7367fc6052a49b781efbcfc138f3b68fe79ddd0c2fMike McCormack tasklet_kill(&rtlpriv->works.irq_tasklet); 740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<3> Disable Adapter */ 760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->hw_disable(hw); 770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 78324732848c42bf79988479ee1b4359e15f08154bLarry Finger return true; 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, 844b9d8d67b44aae18e1c4b71281f5cfc0f2105cf6Mike McCormack u32 changesource) 850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 887ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger bool actionallowed = false; 890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger switch (state_toset) { 910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFON: 920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason &= (~changesource); 930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((changesource == RF_CHANGE_BY_HW) && 95e10542c447abf7c840931ff12f7d0dee976ca2eaMike McCormack (ppsc->hwradiooff)) { 967ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = false; 970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (!ppsc->rfoff_reason) { 1000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason = 0; 1017ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFOFF: 1070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 10823677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if ((changesource == RF_CHANGE_BY_HW) && !ppsc->hwradiooff) { 1097ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = true; 1100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1137ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFSLEEP: 1170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1187ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger default: 1220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, 123f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "switch case not processed\n"); 1240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1277ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (actionallowed) 1280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); 1290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1307ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger return actionallowed; 1310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 1320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_set_rf_state); 1330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) 1350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 1360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 1370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 1380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 1390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1407ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = true; 1410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 142099fb8ab1e57e5d609ac686cc0ab6d1835a79155Larry Finger if (ppsc->inactive_pwrstate == ERFON && 143cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlhal->interface == INTF_PCI) { 1440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && 145cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && 1460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 1470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 148cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 1490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1524b9d8d67b44aae18e1c4b71281f5cfc0f2105cf6Mike McCormack rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, RF_CHANGE_BY_IPS); 1530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->inactive_pwrstate == ERFOFF && 1550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 156cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && 157cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 1580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->enable_aspm(hw); 159cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 1600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1637ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = false; 1640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 1650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off_wq_callback(void *data) 1670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 1680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_works *rtlworks = 1690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq); 1700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct ieee80211_hw *hw = rtlworks->hw; 1710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 1720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 1730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 1740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 1750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 1760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode != NL80211_IFTYPE_STATION) { 1780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 179f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "not station return\n"); 1800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 1810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 18326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (mac->p2p_in_use) 18426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 18526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 186cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->link_state > MAC80211_NOLINK) 187cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 188cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 1890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (is_hal_stop(rtlhal)) 1900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 1910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 1930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 1940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 19526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->cfg->ops->bt_coex_off_before_lps) 19626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->bt_coex_off_before_lps(hw); 19726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 1987ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 1990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 2000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 2020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Do not enter IPS in the following conditions: 2030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(1) RF is already OFF or Sleep 2047ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger *(2) swrf_processing (indicates the IPS is still under going) 2050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(3) Connectted (only disconnected can trigger IPS) 2060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(4) IBSS (send Beacon) 2070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(5) AP mode (send Beacon) 2080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(6) monitor mode (rcv packet) 2090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate == ERFON && 2127ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 2130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (mac->link_state == MAC80211_NOLINK) && 2140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger !mac->act_scanning) { 2150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, 216f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "IPSEnter(): Turn off RF\n"); 2170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFOFF; 2197ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = true; 2200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*rtl_pci_reset_trx_ring(hw); */ 2220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 2230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off(struct ieee80211_hw *hw) 2280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 2320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *because when link with ap, mac80211 will ask us 2330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *to disable nic quickly after scan before linking, 2340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *this will cause link failed, so we delay 100ms here 2350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger queue_delayed_work(rtlpriv->works.rtl_wq, 2370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger &rtlpriv->works.ips_nic_off_wq, MSECS(100)); 2380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 24026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger/* NOTICE: any opmode should exc nic_on, or disable without 24126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger * nic_on may something wrong, like adhoc TP 24226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger */ 2430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_on(struct ieee80211_hw *hw) 2440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 246cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 2470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 249b9116b9a2b5db63187d28f99e038f473fad036dcLarry Finger unsigned long flags; 2500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 251cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->opmode != NL80211_IFTYPE_STATION) 252cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 253cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 254b9116b9a2b5db63187d28f99e038f473fad036dcLarry Finger spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); 2550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2567ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 2570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 2580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate != ERFON && 2607ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 2610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { 2620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFON; 2647ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = false; 2650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 2670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 270b9116b9a2b5db63187d28f99e038f473fad036dcLarry Finger spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags); 2710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2726f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_ips_nic_on); 2730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*for FW LPS*/ 2750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* 2770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Determine if we can set Fw into PS mode 2780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *in current condition.Return TRUE if it 2790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *can enter PS mode. 2800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic bool rtl_get_fwlps_doze(struct ieee80211_hw *hw) 2820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 2850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u32 ps_timediff; 2870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ps_timediff = jiffies_to_msecs(jiffies - 2890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->last_delaylps_stamp_jiffies); 2900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ps_timediff < 2000) { 2920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 293f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n"); 2940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 2950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 2980c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 2990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return true; 3040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* Change current and default preamble mode.*/ 3070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) 3080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 31226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger bool enter_fwlps; 3130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == rt_psmode) 3210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Update power save mode configured. */ 3240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = rt_psmode; 3250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 3270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *<FW control LPS> 3280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *1. Enter PS mode 3290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode 3300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * cmd to set Fw into PS mode. 3310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *2. Leave PS mode 3320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Send H2C fw_pwrmode cmd to Fw to set Fw into Active 3330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * mode and set RPWM to turn RF on. 3340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 3350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 336cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((ppsc->fwctrl_lps) && ppsc->report_linked) { 3370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == EACTIVE) { 3380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 339f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "FW LPS leave ps_mode:%x\n", 340f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches FW_PS_ACTIVE_MODE); 34126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger enter_fwlps = false; 34226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->pwr_mode = FW_PS_ACTIVE_MODE; 34326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->smart_ps = 0; 3440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 34526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_FW_LPS_ACTION, 34626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&enter_fwlps)); 34726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ppsc->p2p_ps_info.opp_ps) 34826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); 3490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 3510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtl_get_fwlps_doze(hw)) { 3520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 353f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "FW LPS enter ps_mode:%x\n", 354f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches ppsc->fwctrl_psmode); 35526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger enter_fwlps = true; 35626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->pwr_mode = ppsc->fwctrl_psmode; 35726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->smart_ps = 2; 3580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 35926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_FW_LPS_ACTION, 36026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&enter_fwlps)); 3610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 3630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Reset the power save related parameters. */ 3640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = EACTIVE; 3650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Enter the leisure power save mode.*/ 3710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_enter(struct ieee80211_hw *hw) 3720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 3750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 377cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!ppsc->fwctrl_lps) 3780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 3810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3837ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (rtlpriv->link_info.busytraffic) 3840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ 3870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->cnt_after_linked < 5) 3880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3940c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3966539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_lock(&rtlpriv->locks.ps_mutex); 3970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 398cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* Idle for a while if we connect to AP a while ago. */ 399cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->cnt_after_linked >= 2) { 400cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->dot11_psmode == EACTIVE) { 401cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 402f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Enter 802.11 power save mode...\n"); 4030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 404cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_lps_set_psmode(hw, EAUTOPS); 4050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 407cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 4086539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_unlock(&rtlpriv->locks.ps_mutex); 4090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 4100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Leave the leisure power save mode.*/ 4120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_leave(struct ieee80211_hw *hw) 4130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 4140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 4150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 4160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 4170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4186539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_lock(&rtlpriv->locks.ps_mutex); 4190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 420cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->fwctrl_lps) { 4210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode != EACTIVE) { 4220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*FIX ME */ 4240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->enable_interrupt(hw); 4250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && 427cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && 4280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 4290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 430cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 4310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 434f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Busy Traffic,Leave 802.11 power save..\n"); 4350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_lps_set_psmode(hw, EACTIVE); 4370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4396539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_unlock(&rtlpriv->locks.ps_mutex); 4400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 441cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 442cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li/* For sw LPS*/ 443cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) 444cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 445cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 446cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 4472c208890c6d4e16076c6664137703ec813e8fa6cJoe Perches struct ieee80211_hdr *hdr = data; 448cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_tim_ie *tim_ie; 449cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 *tim; 450cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 tim_len; 451cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool u_buffed; 452cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool m_buffed; 453cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 454cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->opmode != NL80211_IFTYPE_STATION) 455cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 456cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 457cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.swctrl_lps) 458cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 459cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 460cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->mac80211.link_state != MAC80211_LINKED) 461cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 462cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 463cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.sw_ps_enabled) 464cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 465cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 466cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.fwctrl_lps) 467cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 468cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 469cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) 470cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 471cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 472cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* check if this really is a beacon */ 473cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!ieee80211_is_beacon(hdr->frame_control)) 474cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 475cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 476cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* min. beacon length + FCS_LEN */ 477cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (len <= 40 + FCS_LEN) 478cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 479cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 480cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* and only beacons from the associated BSSID, please */ 48190908e1cd14716f1b989b97003007bfcc7be3d13Julia Lawall if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) 482cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 483cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 484cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_beacon = jiffies; 485cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 486cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); 487cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!tim) 488cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 489cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 490cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (tim[1] < sizeof(*tim_ie)) 491cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 492cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 493cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim_len = tim[1]; 494cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim_ie = (struct ieee80211_tim_ie *) &tim[2]; 495cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 496cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) 497cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.dtim_counter = tim_ie->dtim_count; 498cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 499cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* Check whenever the PHY can be turned off again. */ 500cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 501cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* 1. What about buffered unicast traffic for our AID? */ 502cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u_buffed = ieee80211_check_tim(tim_ie, tim_len, 503cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->mac80211.assoc_id); 504cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 505cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* 2. Maybe the AP wants to send multicast/broadcast data? */ 506cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li m_buffed = tim_ie->bitmap_ctrl & 0x01; 507cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.multi_buffered = m_buffed; 508cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 509cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* unicast will process by mac80211 through 510cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * set ~IEEE80211_CONF_PS, So we just check 511cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * multicast frames here */ 512cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!m_buffed) { 513cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* back to low-power land. and delay is 514cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * prevent null power save frame tx fail */ 515cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li queue_delayed_work(rtlpriv->works.rtl_wq, 516cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li &rtlpriv->works.ps_work, MSECS(5)); 517cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } else { 518f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, 519f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed); 520cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 521cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 5226f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_swlps_beacon); 523cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 524cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rf_awake(struct ieee80211_hw *hw) 525cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 526cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 527cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 528cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 529cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 530cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.swctrl_lps) 531cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 532cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->link_state != MAC80211_LINKED) 533cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 534cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 535cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && 536cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 537cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->intf_ops->disable_aspm(hw); 538cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 539cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 540cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 5416539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_lock(&rtlpriv->locks.ps_mutex); 5424b9d8d67b44aae18e1c4b71281f5cfc0f2105cf6Mike McCormack rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); 5436539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_unlock(&rtlpriv->locks.ps_mutex); 544cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 545cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 546cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rfon_wq_callback(void *data) 547cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 548cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works *rtlworks = 549cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); 550cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_hw *hw = rtlworks->hw; 551cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 552cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_swlps_rf_awake(hw); 553cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 554cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 555cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rf_sleep(struct ieee80211_hw *hw) 556cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 557cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 558cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 559cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 560cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 sleep_intv; 561cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 562cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.sw_ps_enabled) 563cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 564cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 565cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((rtlpriv->sec.being_setkey) || 566cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li (mac->opmode == NL80211_IFTYPE_ADHOC)) 567cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 568cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 569cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ 570cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) 571cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 572cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 573cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->link_info.busytraffic) 574cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 575cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 5766539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_lock(&rtlpriv->locks.ps_mutex); 5774b9d8d67b44aae18e1c4b71281f5cfc0f2105cf6Mike McCormack rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); 5786539306b2c3ceafbc4094cf68c58094c282da053Stanislaw Gruszka mutex_unlock(&rtlpriv->locks.ps_mutex); 579cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 580cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && 581cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 582cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->intf_ops->enable_aspm(hw); 583cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 584cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 585cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 586cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* here is power save alg, when this beacon is DTIM 587cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * we will set sleep time to dtim_period * n; 588cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * when this beacon is not DTIM, we will set sleep 589cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * time to sleep_intv = rtlpriv->psc.dtim_counter or 590cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ 591cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 592cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.dtim_counter == 0) { 593cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (hw->conf.ps_dtim_period == 1) 594cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = hw->conf.ps_dtim_period * 2; 595cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li else 596cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = hw->conf.ps_dtim_period; 597cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } else { 598cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = rtlpriv->psc.dtim_counter; 599cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 600cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 601cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) 602cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = MAX_SW_LPS_SLEEP_INTV; 603cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 604cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* this print should always be dtim_conter = 0 & 605cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * sleep = dtim_period, that meaons, we should 606cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * awake before every dtim */ 607cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, 608f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "dtim_counter:%x will sleep :%d beacon_intv\n", 609f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches rtlpriv->psc.dtim_counter, sleep_intv); 610cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 611cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* we tested that 40ms is enough for sw & hw sw delay */ 612cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, 613cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); 614cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 615cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 616bcfb879432094c267c35a7ff75d953d3a66c193aLarry Fingervoid rtl_lps_change_work_callback(struct work_struct *work) 617bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger{ 618bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger struct rtl_works *rtlworks = 619bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger container_of(work, struct rtl_works, lps_change_work); 620bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger struct ieee80211_hw *hw = rtlworks->hw; 621bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 622bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger 623bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger if (rtlpriv->enter_ps) 624bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger rtl_lps_enter(hw); 625bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger else 626bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger rtl_lps_leave(hw); 627bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger} 6286f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); 629cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 630cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_wq_callback(void *data) 631cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 632cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works *rtlworks = container_of_dwork_rtl(data, 633cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works, 634cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li ps_work); 635cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_hw *hw = rtlworks->hw; 636cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 637cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool ps = false; 638cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 639cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li ps = (hw->conf.flags & IEEE80211_CONF_PS); 640cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 641cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* we can sleep after ps null send ok */ 642cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.state_inap) { 643cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_swlps_rf_sleep(hw); 644cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 645cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.state && !ps) { 646cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - 647cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_action); 648cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 649cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 650cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ps) 651cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_slept = jiffies; 652cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 653cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_action = jiffies; 654cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.state = ps; 655cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 656cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 65726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 65826634c4b1868323f49f8cd24c3493b57819867fdLarry Fingerstatic void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, 65926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger unsigned int len) 66026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 66126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 66226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct ieee80211_mgmt *mgmt = (void *)data; 66326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); 66426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u8 *pos, *end, *ie; 66526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u16 noa_len; 66626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; 66726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u8 noa_num, index, i, noa_index = 0; 66826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger bool find_p2p_ie = false , find_p2p_ps_ie = false; 66926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger pos = (u8 *)mgmt->u.beacon.variable; 67026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger end = data + len; 67126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = NULL; 67226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 67326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger while (pos + 1 < end) { 67426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (pos + 2 + pos[1] > end) 67526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 67626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 67726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (pos[0] == 221 && pos[1] > 4) { 67826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) { 67926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = pos + 2+4; 68026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 68126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 68226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 68326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger pos += 2 + pos[1]; 68426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 68526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 68626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie == NULL) 68726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 68826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger find_p2p_ie = true; 68926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /*to find noa ie*/ 69026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger while (ie + 1 < end) { 691e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte noa_len = READEF2BYTE((__le16 *)&ie[1]); 69226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie + 3 + ie[1] > end) 69326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 69426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 69526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie[0] == 12) { 69626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger find_p2p_ps_ie = true; 69726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if ((noa_len - 2) % 13 != 0) { 69826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, 69926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "P2P notice of absence: invalid length.%d\n", 70026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_len); 70126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 70226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else { 70326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_num = (noa_len - 2) / 13; 70426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 70526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_index = ie[3]; 70626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == 70726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_NONE || noa_index != p2pinfo->noa_index) { 70826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 70926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "update NOA ie.\n"); 71026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_index = noa_index; 71126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->opp_ps = (ie[4] >> 7); 71226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->ctwindow = ie[4] & 0x7F; 71326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_num = noa_num; 71426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index = 5; 71526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger for (i = 0; i < noa_num; i++) { 71626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_count_type[i] = 71726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger READEF1BYTE(ie+index); 71826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 1; 71926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_duration[i] = 720e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 72126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 72226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_interval[i] = 723e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 72426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 72526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_start_time[i] = 726e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 72726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 72826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 72926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 73026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->opp_ps == 1) { 73126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; 73226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* Driver should wait LPS entering 73326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger * CTWindow 73426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger */ 73526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.fw_current_inpsmode) 73626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, 73726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_ENABLE); 73826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->noa_num > 0) { 73926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_NOA; 74026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); 74126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 74226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); 74326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 74426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 74526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 74626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 74726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie += 3 + noa_len; 74826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 74926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 75026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (find_p2p_ie == true) { 75126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) && 75226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (find_p2p_ps_ie == false)) 75326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); 75426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 75526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 75626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 75726634c4b1868323f49f8cd24c3493b57819867fdLarry Fingerstatic void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, 75826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger unsigned int len) 75926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 76026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 76126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct ieee80211_mgmt *mgmt = (void *)data; 76226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); 76326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u8 noa_num, index, i, noa_index = 0; 76426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u8 *pos, *end, *ie; 76526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u16 noa_len; 76626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; 76726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 76826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger pos = (u8 *)&mgmt->u.action.category; 76926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger end = data + len; 77026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = NULL; 77126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 77226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (pos[0] == 0x7f) { 77326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0) 77426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = pos + 3+4; 77526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 77626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 77726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie == NULL) 77826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 77926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 78026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n"); 78126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /*to find noa ie*/ 78226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger while (ie + 1 < end) { 783e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte noa_len = READEF2BYTE((__le16 *)&ie[1]); 78426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie + 3 + ie[1] > end) 78526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 78626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 78726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie[0] == 12) { 78826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n"); 78926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ", 79026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie, noa_len); 79126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if ((noa_len - 2) % 13 != 0) { 79226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 79326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "P2P notice of absence: invalid length.%d\n", 79426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_len); 79526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 79626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else { 79726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_num = (noa_len - 2) / 13; 79826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 79926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_index = ie[3]; 80026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == 80126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_NONE || noa_index != p2pinfo->noa_index) { 80226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_index = noa_index; 80326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->opp_ps = (ie[4] >> 7); 80426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->ctwindow = ie[4] & 0x7F; 80526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_num = noa_num; 80626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index = 5; 80726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger for (i = 0; i < noa_num; i++) { 80826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_count_type[i] = 80926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger READEF1BYTE(ie+index); 81026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 1; 81126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_duration[i] = 812e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 81326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 81426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_interval[i] = 815e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 81626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 81726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_start_time[i] = 818e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 81926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 82026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 82126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 82226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->opp_ps == 1) { 82326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; 82426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* Driver should wait LPS entering 82526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger * CTWindow 82626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger */ 82726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.fw_current_inpsmode) 82826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, 82926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_ENABLE); 83026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->noa_num > 0) { 83126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_NOA; 83226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); 83326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 83426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); 83526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 83626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 83726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 83826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 83926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie += 3 + noa_len; 84026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 84126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 84226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 84326634c4b1868323f49f8cd24c3493b57819867fdLarry Fingervoid rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) 84426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 84526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 84626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); 84726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); 84826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 84926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n", p2p_ps_state); 85026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger switch (p2p_ps_state) { 85126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_DISABLE: 85226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_state = p2p_ps_state; 85326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 85426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_P2P_PS_OFFLOAD, 85526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&p2p_ps_state)); 85626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 85726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_index = 0; 85826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->ctwindow = 0; 85926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->opp_ps = 0; 86026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_num = 0; 86126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_NONE; 86226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlps->fw_current_inpsmode == true) { 86326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlps->smart_ps == 0) { 86426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlps->smart_ps = 2; 86526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 86626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_PWRMODE, 86726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&rtlps->pwr_mode)); 86826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 86926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 87026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 87126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_ENABLE: 87226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 87326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_state = p2p_ps_state; 87426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 87526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->ctwindow > 0) { 87626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlps->smart_ps != 0) { 87726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlps->smart_ps = 0; 87826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 87926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_PWRMODE, 88026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&rtlps->pwr_mode)); 88126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 88226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 88326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 88426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_P2P_PS_OFFLOAD, 88526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&p2p_ps_state)); 88626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 88726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 88826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_SCAN: 88926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_SCAN_DONE: 89026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_ALLSTASLEEP: 89126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 89226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_state = p2p_ps_state; 89326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 89426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_P2P_PS_OFFLOAD, 89526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&p2p_ps_state)); 89626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 89726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 89826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger default: 89926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 90026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 90126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 90226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "ctwindow %x oppps %x\n", p2pinfo->ctwindow, p2pinfo->opp_ps); 90326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 90426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "count %x duration %x index %x interval %x start time %x noa num %x\n", 90526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_count_type[0], p2pinfo->noa_duration[0], 90626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_index, p2pinfo->noa_interval[0], 90726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_start_time[0], p2pinfo->noa_num); 90826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n"); 90926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 91026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 91126634c4b1868323f49f8cd24c3493b57819867fdLarry Fingervoid rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) 91226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 91326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 91426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 91526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct ieee80211_hdr *hdr = (void *)data; 91626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 91726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (!mac->p2p) 91826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 91926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (mac->link_state != MAC80211_LINKED) 92026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 92126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* min. beacon length + FCS_LEN */ 92226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (len <= 40 + FCS_LEN) 92326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 92426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 92526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* and only beacons from the associated BSSID, please */ 92690908e1cd14716f1b989b97003007bfcc7be3d13Julia Lawall if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) 92726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 92826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 92926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* check if this really is a beacon */ 93026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (!(ieee80211_is_beacon(hdr->frame_control) || 93126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ieee80211_is_probe_resp(hdr->frame_control) || 93226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ieee80211_is_action(hdr->frame_control))) 93326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 93426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 93526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ieee80211_is_action(hdr->frame_control)) 93626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_action_ie(hw, data, len - FCS_LEN); 93726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger else 93826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_noa_ie(hw, data, len - FCS_LEN); 93926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 9406f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_p2p_info); 941