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 * The full GNU General Public License is included in this distribution in the 150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * file called LICENSE. 160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Contact Information: 180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * wlanfae <wlanfae@realtek.com> 190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, 200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Hsinchu 300, Taiwan. 210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Larry Finger <Larry.Finger@lwfinger.net> 230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * 240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *****************************************************************************/ 250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "wifi.h" 270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "base.h" 280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger#include "ps.h" 29d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger#include <linux/export.h> 30d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger#include "btcoexist/rtl_btc.h" 3125b13dbc38a74b76da5746d75867e306b70035bdLarry Finger 320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_enable_nic(struct ieee80211_hw *hw) 330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<1> reset trx ring */ 390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlhal->interface == INTF_PCI) 400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->reset_trx_ring(hw); 410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (is_hal_stop(rtlhal)) 430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 44f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Driver is already down!\n"); 450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Enable Adapter */ 47b0302aba812bcc39291cdab9ad7e37008f352a91Larry Finger if (rtlpriv->cfg->ops->hw_init(hw)) 482e8c5e56b307271c2dab6f8bfd1d8a3822ca2390Olivier Langlois return false; 490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); 500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<3> Enable Interrupt */ 520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->enable_interrupt(hw); 530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<enable timer> */ 550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_watch_dog_timer_callback((unsigned long)hw); 560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 57cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return true; 580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_enable_nic); 600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_disable_nic(struct ieee80211_hw *hw) 620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<1> Stop all timer */ 660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_deinit_deferred_work(hw); 670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<2> Disable Interrupt */ 690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->disable_interrupt(hw); 7067fc6052a49b781efbcfc138f3b68fe79ddd0c2fMike McCormack tasklet_kill(&rtlpriv->works.irq_tasklet); 710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*<3> Disable Adapter */ 730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->hw_disable(hw); 740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 75324732848c42bf79988479ee1b4359e15f08154bLarry Finger return true; 760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_disable_nic); 780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerbool rtl_ps_set_rf_state(struct ieee80211_hw *hw, 800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate state_toset, 81d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger u32 changesource, bool protect_or_not) 820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 85d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger enum rf_pwrstate rtstate; 867ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger bool actionallowed = false; 87d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger u16 rfwait_cnt = 0; 88d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 89d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (protect_or_not) 90d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger goto no_protect; 91d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 92d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger /*Only one thread can change 93d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger *the RF state at one time, and others 94d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger *should wait to be executed. 95d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger */ 96d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger while (true) { 97d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock(&rtlpriv->locks.rf_ps_lock); 98d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (ppsc->rfchange_inprogress) { 99d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock(&rtlpriv->locks.rf_ps_lock); 100d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 101d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 102d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger "RF Change in progress! Wait to set..state_toset(%d).\n", 103d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger state_toset); 104d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 105d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger /* Set RF after the previous action is done. */ 106d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger while (ppsc->rfchange_inprogress) { 107d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rfwait_cnt++; 108d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger mdelay(1); 109d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger /*Wait too long, return false to avoid 110d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger *to be stuck here. 111d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger */ 112d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (rfwait_cnt > 100) 113d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger return false; 114d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger } 115d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger } else { 116d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger ppsc->rfchange_inprogress = true; 117d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock(&rtlpriv->locks.rf_ps_lock); 118d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger break; 119d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger } 120d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger } 121d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 122d3feae41a3473a0f7b431d6af4e092865d586e52Larry Fingerno_protect: 123d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtstate = ppsc->rfpwr_state; 1240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger switch (state_toset) { 1260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFON: 1270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason &= (~changesource); 1280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((changesource == RF_CHANGE_BY_HW) && 130e10542c447abf7c840931ff12f7d0dee976ca2eaMike McCormack (ppsc->hwradiooff)) { 1317ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = false; 1320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (!ppsc->rfoff_reason) { 1350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason = 0; 1367ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFOFF: 1420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 14323677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if ((changesource == RF_CHANGE_BY_HW) && !ppsc->hwradiooff) { 1447ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->hwradiooff = true; 1450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1487ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger case ERFSLEEP: 1520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason |= changesource; 1537ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger actionallowed = true; 1540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger default: 1570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, 158f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "switch case not processed\n"); 1590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger break; 1600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1627ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (actionallowed) 1630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset); 1640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 165d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (!protect_or_not) { 166d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock(&rtlpriv->locks.rf_ps_lock); 167d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger ppsc->rfchange_inprogress = false; 168d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock(&rtlpriv->locks.rf_ps_lock); 169d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger } 170d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 1717ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger return actionallowed; 1720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 1730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry FingerEXPORT_SYMBOL(rtl_ps_set_rf_state); 1740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) 1760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 1770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 1780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 1790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 1800c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1817ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = true; 1820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 183099fb8ab1e57e5d609ac686cc0ab6d1835a79155Larry Finger if (ppsc->inactive_pwrstate == ERFON && 184cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlhal->interface == INTF_PCI) { 1850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && 186cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && 1870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 1880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 189cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 1900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 1920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 193d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, 194d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger RF_CHANGE_BY_IPS, false); 1950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 1960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->inactive_pwrstate == ERFOFF && 1970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 198cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && 199d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 2000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->enable_aspm(hw); 201cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 2020c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2057ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->swrf_processing = false; 2060c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off_wq_callback(void *data) 2090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_works *rtlworks = 2110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq); 2120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct ieee80211_hw *hw = rtlworks->hw; 2130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 2150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 2160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 2180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode != NL80211_IFTYPE_STATION) { 2200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, 221f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "not station return\n"); 2220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 22526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (mac->p2p_in_use) 22626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 22726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 228cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->link_state > MAC80211_NOLINK) 229cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 230cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 2310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (is_hal_stop(rtlhal)) 2320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 2350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 2360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 23726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->cfg->ops->bt_coex_off_before_lps) 23826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->bt_coex_off_before_lps(hw); 23926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 2407ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 2410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 2420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 2440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Do not enter IPS in the following conditions: 2450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(1) RF is already OFF or Sleep 2467ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger *(2) swrf_processing (indicates the IPS is still under going) 2470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(3) Connectted (only disconnected can trigger IPS) 2480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(4) IBSS (send Beacon) 2490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(5) AP mode (send Beacon) 2500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *(6) monitor mode (rcv packet) 2510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate == ERFON && 2547ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 2550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger (mac->link_state == MAC80211_NOLINK) && 2560c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger !mac->act_scanning) { 2570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, 258f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "IPSEnter(): Turn off RF\n"); 2590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFOFF; 2617ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = true; 2620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 263d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger /* call before RF off */ 264d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (rtlpriv->cfg->ops->get_btc_status()) 265d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv, 266d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger ppsc->inactive_pwrstate); 267d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 2680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*rtl_pci_reset_trx_ring(hw); */ 2690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 2700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 2720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 2740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_off(struct ieee80211_hw *hw) 2750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 278d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger /* because when link with ap, mac80211 will ask us 279d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger * to disable nic quickly after scan before linking, 280d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger * this will cause link failed, so we delay 100ms here 2810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 2820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger queue_delayed_work(rtlpriv->works.rtl_wq, 2830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger &rtlpriv->works.ips_nic_off_wq, MSECS(100)); 2840c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 2850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 28626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger/* NOTICE: any opmode should exc nic_on, or disable without 28726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger * nic_on may something wrong, like adhoc TP 28826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger */ 2890c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_ips_nic_on(struct ieee80211_hw *hw) 2900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 2910c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 2920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 2930c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger enum rf_pwrstate rtstate; 294cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 295d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); 2960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 297d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock(&rtlpriv->locks.ips_lock); 2987ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (ppsc->inactiveps) { 2990c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtstate = ppsc->rfpwr_state; 3000c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3010c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtstate != ERFON && 3027ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger !ppsc->swrf_processing && 3030c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) { 3040c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->inactive_pwrstate = ERFON; 3067ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger ppsc->in_powersavemode = false; 3070c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger _rtl_ps_inactive_ps(hw); 308d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger /* call after RF on */ 309d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (rtlpriv->cfg->ops->get_btc_status()) 310d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv, 311d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger ppsc->inactive_pwrstate); 3120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 314d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock(&rtlpriv->locks.ips_lock); 3150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3166f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_ips_nic_on); 3170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*for FW LPS*/ 3190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* 3210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *Determine if we can set Fw into PS mode 3220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *in current condition.Return TRUE if it 3230c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *can enter PS mode. 3240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 3250c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingerstatic bool rtl_get_fwlps_doze(struct ieee80211_hw *hw) 3260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 3300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger u32 ps_timediff; 3310c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ps_timediff = jiffies_to_msecs(jiffies - 3330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->last_delaylps_stamp_jiffies); 3340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ps_timediff < 2000) { 3360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 337f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n"); 3380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 3400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3440c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return false; 3460c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3470c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return true; 3480c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 3490c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3500c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/* Change current and default preamble mode.*/ 351d3feae41a3473a0f7b431d6af4e092865d586e52Larry Fingervoid rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) 3520c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 3530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 3540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 3550c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 35626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger bool enter_fwlps; 3570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3580c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 3590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 3620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == rt_psmode) 3650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 3660c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Update power save mode configured. */ 3680c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = rt_psmode; 3690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 3700c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* 3710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *<FW control LPS> 3720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *1. Enter PS mode 3730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode 3740c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * cmd to set Fw into PS mode. 3750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger *2. Leave PS mode 3760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * Send H2C fw_pwrmode cmd to Fw to set Fw into Active 3770c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger * mode and set RPWM to turn RF on. 3780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger */ 3790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 380cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((ppsc->fwctrl_lps) && ppsc->report_linked) { 3810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode == EACTIVE) { 3820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 383f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "FW LPS leave ps_mode:%x\n", 384d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger FW_PS_ACTIVE_MODE); 38526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger enter_fwlps = false; 38626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->pwr_mode = FW_PS_ACTIVE_MODE; 38726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->smart_ps = 0; 388d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION, 389d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger (u8 *)(&enter_fwlps)); 39026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ppsc->p2p_ps_info.opp_ps) 391d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtl_p2p_ps_cmd(hw , P2P_PS_ENABLE); 3920c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 393d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (rtlpriv->cfg->ops->get_btc_status()) 394d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode); 3950c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 3960c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtl_get_fwlps_doze(hw)) { 3970c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 398f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "FW LPS enter ps_mode:%x\n", 399f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches ppsc->fwctrl_psmode); 400d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (rtlpriv->cfg->ops->get_btc_status()) 401d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode); 40226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger enter_fwlps = true; 40326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->pwr_mode = ppsc->fwctrl_psmode; 40426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ppsc->smart_ps = 2; 4050c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 40626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_FW_LPS_ACTION, 40726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (u8 *)(&enter_fwlps)); 4080c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4090c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } else { 4100c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /* Reset the power save related parameters. */ 4110c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger ppsc->dot11_psmode = EACTIVE; 4120c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4130c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4140c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4150c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 4160c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4170c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Enter the leisure power save mode.*/ 4180c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_enter(struct ieee80211_hw *hw) 4190c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 4200c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 4210c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 4220c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 423d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger unsigned long flag; 4240c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 425cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!ppsc->fwctrl_lps) 4260c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4270c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4280c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (rtlpriv->sec.being_setkey) 4290c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4300c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4317ea4724036ed17ec811cb8082af7760f04484ef7Larry Finger if (rtlpriv->link_info.busytraffic) 4320c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4330c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4340c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ 4350c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->cnt_after_linked < 5) 4360c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4370c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4380c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->opmode == NL80211_IFTYPE_ADHOC) 4390c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4400c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4410c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (mac->link_state != MAC80211_LINKED) 4420c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger return; 4430c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 444d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 4450c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 446cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* Idle for a while if we connect to AP a while ago. */ 447cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->cnt_after_linked >= 2) { 448cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->dot11_psmode == EACTIVE) { 449cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 450f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Enter 802.11 power save mode...\n"); 4510c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 452cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_lps_set_psmode(hw, EAUTOPS); 4530c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4540c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 455cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 456d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 4570c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 458d3feae41a3473a0f7b431d6af4e092865d586e52Larry FingerEXPORT_SYMBOL(rtl_lps_enter); 4590c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4600c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger/*Leave the leisure power save mode.*/ 4610c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Fingervoid rtl_lps_leave(struct ieee80211_hw *hw) 4620c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger{ 4630c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 4640c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 4650c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 466d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger unsigned long flag; 4670c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 468d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 4690c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 470cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->fwctrl_lps) { 4710c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->dot11_psmode != EACTIVE) { 4720c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4730c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger /*FIX ME */ 474d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger /*rtlpriv->cfg->ops->enable_interrupt(hw); */ 4750c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4760c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && 477cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && 4780c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlhal->interface == INTF_PCI) { 4790c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtlpriv->intf_ops->disable_aspm(hw); 480cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 4810c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4820c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4830c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, 484f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "Busy Traffic,Leave 802.11 power save..\n"); 4850c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger 4860c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger rtl_lps_set_psmode(hw, EACTIVE); 4870c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 4880c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger } 489d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 4900c8173385e549f95cd80c3fff5aab87b4f881d8dLarry Finger} 491d3feae41a3473a0f7b431d6af4e092865d586e52Larry FingerEXPORT_SYMBOL(rtl_lps_leave); 492cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 493cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li/* For sw LPS*/ 494cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) 495cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 496cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 497cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 4982c208890c6d4e16076c6664137703ec813e8fa6cJoe Perches struct ieee80211_hdr *hdr = data; 499cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_tim_ie *tim_ie; 500cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 *tim; 501cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 tim_len; 502cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool u_buffed; 503cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool m_buffed; 504cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 505cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->opmode != NL80211_IFTYPE_STATION) 506cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 507cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 508cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.swctrl_lps) 509cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 510cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 511cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->mac80211.link_state != MAC80211_LINKED) 512cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 513cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 514cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.sw_ps_enabled) 515cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 516cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 517cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.fwctrl_lps) 518cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 519cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 520cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) 521cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 522cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 523cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* check if this really is a beacon */ 524cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!ieee80211_is_beacon(hdr->frame_control)) 525cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 526cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 527cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* min. beacon length + FCS_LEN */ 528cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (len <= 40 + FCS_LEN) 529cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 530cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 531cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* and only beacons from the associated BSSID, please */ 53290908e1cd14716f1b989b97003007bfcc7be3d13Julia Lawall if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) 533cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 534cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 535cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_beacon = jiffies; 536cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 537cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); 538cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!tim) 539cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 540cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 541cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (tim[1] < sizeof(*tim_ie)) 542cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 543cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 544cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim_len = tim[1]; 545cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li tim_ie = (struct ieee80211_tim_ie *) &tim[2]; 546cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 547cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) 548cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.dtim_counter = tim_ie->dtim_count; 549cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 550cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* Check whenever the PHY can be turned off again. */ 551cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 552cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* 1. What about buffered unicast traffic for our AID? */ 553cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u_buffed = ieee80211_check_tim(tim_ie, tim_len, 554cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->mac80211.assoc_id); 555cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 556cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* 2. Maybe the AP wants to send multicast/broadcast data? */ 557cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li m_buffed = tim_ie->bitmap_ctrl & 0x01; 558cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.multi_buffered = m_buffed; 559cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 560cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* unicast will process by mac80211 through 561cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * set ~IEEE80211_CONF_PS, So we just check 562cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * multicast frames here */ 563cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!m_buffed) { 564cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* back to low-power land. and delay is 565cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * prevent null power save frame tx fail */ 566cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li queue_delayed_work(rtlpriv->works.rtl_wq, 567d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger &rtlpriv->works.ps_work, MSECS(5)); 568cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } else { 569f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, 570f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed); 571cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 572cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 5736f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_swlps_beacon); 574cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 575cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rf_awake(struct ieee80211_hw *hw) 576cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 577cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 578cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 579cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 580d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger unsigned long flag; 581cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 582cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.swctrl_lps) 583cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 584cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (mac->link_state != MAC80211_LINKED) 585cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 586cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 587cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && 588d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 589cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->intf_ops->disable_aspm(hw); 590cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 591cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 592cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 593d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 594d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); 595d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 596cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 597cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 598cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rfon_wq_callback(void *data) 599cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 600cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works *rtlworks = 601cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); 602cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_hw *hw = rtlworks->hw; 603cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 604cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_swlps_rf_awake(hw); 605cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 606cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 607cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_rf_sleep(struct ieee80211_hw *hw) 608cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 609cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 610cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 611cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 612d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger unsigned long flag; 613cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li u8 sleep_intv; 614cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 615cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (!rtlpriv->psc.sw_ps_enabled) 616cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 617cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 618cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((rtlpriv->sec.being_setkey) || 619cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li (mac->opmode == NL80211_IFTYPE_ADHOC)) 620cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 621cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 622cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ 623cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) 624cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 625cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 626cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->link_info.busytraffic) 627cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li return; 628cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 629d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock(&rtlpriv->locks.rf_ps_lock); 630d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (rtlpriv->psc.rfchange_inprogress) { 631d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock(&rtlpriv->locks.rf_ps_lock); 632d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger return; 633d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger } 634d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock(&rtlpriv->locks.rf_ps_lock); 635d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 636d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); 637d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false); 638d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); 639cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 640cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && 641d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { 642cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->intf_ops->enable_aspm(hw); 643cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); 644cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 645cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 646cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* here is power save alg, when this beacon is DTIM 647cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * we will set sleep time to dtim_period * n; 648cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * when this beacon is not DTIM, we will set sleep 649cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * time to sleep_intv = rtlpriv->psc.dtim_counter or 650cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ 651cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 652cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.dtim_counter == 0) { 653cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (hw->conf.ps_dtim_period == 1) 654cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = hw->conf.ps_dtim_period * 2; 655cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li else 656cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = hw->conf.ps_dtim_period; 657cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } else { 658cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = rtlpriv->psc.dtim_counter; 659cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 660cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 661cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) 662cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li sleep_intv = MAX_SW_LPS_SLEEP_INTV; 663cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 664cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* this print should always be dtim_conter = 0 & 665cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * sleep = dtim_period, that meaons, we should 666cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li * awake before every dtim */ 667cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, 668f30d7507a8116e2099a9135c873411db8c0a3dc6Joe Perches "dtim_counter:%x will sleep :%d beacon_intv\n", 669d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtlpriv->psc.dtim_counter, sleep_intv); 670cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 671cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* we tested that 40ms is enough for sw & hw sw delay */ 672cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, 673cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); 674cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 675cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 676bcfb879432094c267c35a7ff75d953d3a66c193aLarry Fingervoid rtl_lps_change_work_callback(struct work_struct *work) 677bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger{ 678bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger struct rtl_works *rtlworks = 679bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger container_of(work, struct rtl_works, lps_change_work); 680bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger struct ieee80211_hw *hw = rtlworks->hw; 681bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 682bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger 683bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger if (rtlpriv->enter_ps) 684bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger rtl_lps_enter(hw); 685bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger else 686bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger rtl_lps_leave(hw); 687bcfb879432094c267c35a7ff75d953d3a66c193aLarry Finger} 6886f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); 689cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 690cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Livoid rtl_swlps_wq_callback(void *data) 691cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li{ 692cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works *rtlworks = container_of_dwork_rtl(data, 693cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_works, 694cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li ps_work); 695cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct ieee80211_hw *hw = rtlworks->hw; 696cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li struct rtl_priv *rtlpriv = rtl_priv(hw); 697cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li bool ps = false; 698cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 699cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li ps = (hw->conf.flags & IEEE80211_CONF_PS); 700cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 701cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li /* we can sleep after ps null send ok */ 702cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.state_inap) { 703cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtl_swlps_rf_sleep(hw); 704cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 705cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (rtlpriv->psc.state && !ps) { 706cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - 707d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtlpriv->psc.last_action); 708cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 709cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 710cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li if (ps) 711cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_slept = jiffies; 712cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li 713cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.last_action = jiffies; 714cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li rtlpriv->psc.state = ps; 715cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li } 716cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3Chaoming_Li} 71726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 71826634c4b1868323f49f8cd24c3493b57819867fdLarry Fingerstatic void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, 71926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger unsigned int len) 72026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 72126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 7221851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches struct ieee80211_mgmt *mgmt = data; 72326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); 72426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u8 *pos, *end, *ie; 72526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u16 noa_len; 72626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; 727d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger u8 noa_num, index , i, noa_index = 0; 72826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger bool find_p2p_ie = false , find_p2p_ps_ie = false; 72926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger pos = (u8 *)mgmt->u.beacon.variable; 73026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger end = data + len; 73126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = NULL; 73226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 73326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger while (pos + 1 < end) { 73426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (pos + 2 + pos[1] > end) 73526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 73626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 73726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (pos[0] == 221 && pos[1] > 4) { 73826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) { 73926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = pos + 2+4; 74026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 74126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 74226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 74326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger pos += 2 + pos[1]; 74426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 74526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 74626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie == NULL) 74726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 74826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger find_p2p_ie = true; 74926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /*to find noa ie*/ 75026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger while (ie + 1 < end) { 751e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte noa_len = READEF2BYTE((__le16 *)&ie[1]); 75226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie + 3 + ie[1] > end) 75326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 75426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 75526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie[0] == 12) { 75626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger find_p2p_ps_ie = true; 75726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if ((noa_len - 2) % 13 != 0) { 75826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, 75926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "P2P notice of absence: invalid length.%d\n", 76026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_len); 76126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 76226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else { 76326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_num = (noa_len - 2) / 13; 76426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 76526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_index = ie[3]; 76626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == 76726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_NONE || noa_index != p2pinfo->noa_index) { 76826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 76926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "update NOA ie.\n"); 77026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_index = noa_index; 77126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->opp_ps = (ie[4] >> 7); 77226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->ctwindow = ie[4] & 0x7F; 77326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_num = noa_num; 77426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index = 5; 77526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger for (i = 0; i < noa_num; i++) { 77626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_count_type[i] = 777d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger READEF1BYTE(ie+index); 77826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 1; 77926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_duration[i] = 780e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 78126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 78226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_interval[i] = 783e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 78426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 78526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_start_time[i] = 786e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 78726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 78826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 78926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 79026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->opp_ps == 1) { 79126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; 79226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* Driver should wait LPS entering 79326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger * CTWindow 79426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger */ 79526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.fw_current_inpsmode) 79626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, 79726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_ENABLE); 79826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->noa_num > 0) { 79926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_NOA; 80026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); 80126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 80226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); 80326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 80426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 805d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger break; 80626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 80726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie += 3 + noa_len; 80826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 80926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 81026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (find_p2p_ie == true) { 81126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) && 81226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger (find_p2p_ps_ie == false)) 81326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); 81426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 81526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 81626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 81726634c4b1868323f49f8cd24c3493b57819867fdLarry Fingerstatic void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, 81826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger unsigned int len) 81926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 82026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 8211851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches struct ieee80211_mgmt *mgmt = data; 82226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); 823d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger u8 noa_num, index , i , noa_index = 0; 82426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u8 *pos, *end, *ie; 82526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger u16 noa_len; 82626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09}; 82726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 82826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger pos = (u8 *)&mgmt->u.action.category; 82926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger end = data + len; 83026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = NULL; 83126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 83226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (pos[0] == 0x7f) { 83326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0) 83426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie = pos + 3+4; 83526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 83626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 83726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie == NULL) 83826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 83926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 84026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n"); 84126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /*to find noa ie*/ 84226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger while (ie + 1 < end) { 843e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte noa_len = READEF2BYTE((__le16 *)&ie[1]); 84426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie + 3 + ie[1] > end) 84526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 84626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 84726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ie[0] == 12) { 84826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n"); 84926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ", 85026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie, noa_len); 85126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if ((noa_len - 2) % 13 != 0) { 85226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 85326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "P2P notice of absence: invalid length.%d\n", 85426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_len); 85526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 85626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else { 85726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_num = (noa_len - 2) / 13; 85826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 85926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger noa_index = ie[3]; 86026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == 86126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_NONE || noa_index != p2pinfo->noa_index) { 86226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_index = noa_index; 86326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->opp_ps = (ie[4] >> 7); 86426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->ctwindow = ie[4] & 0x7F; 86526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_num = noa_num; 86626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index = 5; 86726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger for (i = 0; i < noa_num; i++) { 86826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_count_type[i] = 869d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger READEF1BYTE(ie+index); 87026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 1; 87126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_duration[i] = 872e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 87326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 87426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_interval[i] = 875e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 87626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 87726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_start_time[i] = 878e5b417e73efa52b9179ce2a2b7676f08425c62e3Mark Schulte READEF4BYTE((__le32 *)ie+index); 87926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger index += 4; 88026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 88126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 88226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->opp_ps == 1) { 88326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW; 88426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* Driver should wait LPS entering 88526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger * CTWindow 88626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger */ 88726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlpriv->psc.fw_current_inpsmode) 88826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, 88926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger P2P_PS_ENABLE); 89026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->noa_num > 0) { 89126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_NOA; 89226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE); 89326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 89426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); 89526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 89626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 897d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger break; 89826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 89926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ie += 3 + noa_len; 90026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 90126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 90226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 903d3feae41a3473a0f7b431d6af4e092865d586e52Larry Fingervoid rtl_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state) 90426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 90526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 90626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); 90726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info); 90826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 909d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n" , p2p_ps_state); 91026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger switch (p2p_ps_state) { 91126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_DISABLE: 91226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_state = p2p_ps_state; 9131851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, 9141851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches &p2p_ps_state); 91526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_index = 0; 91626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->ctwindow = 0; 91726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->opp_ps = 0; 91826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->noa_num = 0; 91926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_mode = P2P_PS_NONE; 920d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger if (rtlps->fw_current_inpsmode) { 92126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlps->smart_ps == 0) { 92226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlps->smart_ps = 2; 92326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 92426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_PWRMODE, 9251851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches &rtlps->pwr_mode); 92626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 927d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 92826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 92926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 93026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_ENABLE: 93126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 93226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_state = p2p_ps_state; 93326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 93426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->ctwindow > 0) { 93526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (rtlps->smart_ps != 0) { 93626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlps->smart_ps = 0; 93726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 93826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_PWRMODE, 9391851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches &rtlps->pwr_mode); 94026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 94126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 94226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 94326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_P2P_PS_OFFLOAD, 9441851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches &p2p_ps_state); 945d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger 94626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 94726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 94826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_SCAN: 94926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_SCAN_DONE: 95026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger case P2P_PS_ALLSTASLEEP: 95126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) { 95226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger p2pinfo->p2p_ps_state = p2p_ps_state; 95326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger rtlpriv->cfg->ops->set_hw_reg(hw, 95426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger HW_VAR_H2C_FW_P2P_PS_OFFLOAD, 9551851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches &p2p_ps_state); 95626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 95726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 95826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger default: 95926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger break; 96026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger } 96126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 962d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger "ctwindow %x oppps %x\n", 963d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger p2pinfo->ctwindow , p2pinfo->opp_ps); 96426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, 96526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger "count %x duration %x index %x interval %x start time %x noa num %x\n", 966d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger p2pinfo->noa_count_type[0], 967d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger p2pinfo->noa_duration[0], 968d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger p2pinfo->noa_index, 969d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger p2pinfo->noa_interval[0], 970d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger p2pinfo->noa_start_time[0], 971d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger p2pinfo->noa_num); 97226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n"); 97326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 97426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 97526634c4b1868323f49f8cd24c3493b57819867fdLarry Fingervoid rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) 97626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger{ 97726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_priv *rtlpriv = rtl_priv(hw); 97826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 9791851cb4a0f08ba0600103203c4b52e53c744f59cJoe Perches struct ieee80211_hdr *hdr = data; 98026634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 98126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (!mac->p2p) 98226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 98326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (mac->link_state != MAC80211_LINKED) 98426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 98526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* min. beacon length + FCS_LEN */ 98626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (len <= 40 + FCS_LEN) 98726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 98826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 98926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* and only beacons from the associated BSSID, please */ 99090908e1cd14716f1b989b97003007bfcc7be3d13Julia Lawall if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) 99126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 99226634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 99326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger /* check if this really is a beacon */ 99426634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (!(ieee80211_is_beacon(hdr->frame_control) || 99526634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ieee80211_is_probe_resp(hdr->frame_control) || 99626634c4b1868323f49f8cd24c3493b57819867fdLarry Finger ieee80211_is_action(hdr->frame_control))) 99726634c4b1868323f49f8cd24c3493b57819867fdLarry Finger return; 99826634c4b1868323f49f8cd24c3493b57819867fdLarry Finger 99926634c4b1868323f49f8cd24c3493b57819867fdLarry Finger if (ieee80211_is_action(hdr->frame_control)) 1000d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtl_p2p_action_ie(hw , data , len - FCS_LEN); 100126634c4b1868323f49f8cd24c3493b57819867fdLarry Finger else 1002d3feae41a3473a0f7b431d6af4e092865d586e52Larry Finger rtl_p2p_noa_ie(hw , data , len - FCS_LEN); 100326634c4b1868323f49f8cd24c3493b57819867fdLarry Finger} 10046f334c2b3966f10cbd089bb124ec0e114d8d8c77Larry FingerEXPORT_SYMBOL_GPL(rtl_p2p_info); 1005