linux/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
<<
>>
Prefs
   1/******************************************************************************
   2 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
   3 *
   4 * Based on the r8180 driver, which is:
   5 * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of version 2 of the GNU General Public License as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * The full GNU General Public License is included in this distribution in the
  16 * file called LICENSE.
  17 *
  18 * Contact Information:
  19 * wlanfae <wlanfae@realtek.com>
  20 *****************************************************************************/
  21#include "rtl_ps.h"
  22#include "rtl_core.h"
  23#include "r8192E_phy.h"
  24#include "r8192E_phyreg.h"
  25#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */
  26#include "r8192E_cmdpkt.h"
  27#include <linux/jiffies.h>
  28
  29static void _rtl92e_hw_sleep(struct net_device *dev)
  30{
  31        struct r8192_priv *priv = rtllib_priv(dev);
  32        unsigned long flags = 0;
  33
  34        spin_lock_irqsave(&priv->rf_ps_lock, flags);
  35        if (priv->RFChangeInProgress) {
  36                spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
  37                RT_TRACE(COMP_DBG,
  38                         "_rtl92e_hw_sleep(): RF Change in progress!\n");
  39                return;
  40        }
  41        spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
  42        RT_TRACE(COMP_DBG, "%s()============>come to sleep down\n", __func__);
  43
  44        rtl92e_set_rf_state(dev, eRfSleep, RF_CHANGE_BY_PS);
  45}
  46
  47void rtl92e_hw_sleep_wq(void *data)
  48{
  49        struct rtllib_device *ieee = container_of_dwork_rsl(data,
  50                                     struct rtllib_device, hw_sleep_wq);
  51        struct net_device *dev = ieee->dev;
  52
  53        _rtl92e_hw_sleep(dev);
  54}
  55
  56void rtl92e_hw_wakeup(struct net_device *dev)
  57{
  58        struct r8192_priv *priv = rtllib_priv(dev);
  59        unsigned long flags = 0;
  60
  61        spin_lock_irqsave(&priv->rf_ps_lock, flags);
  62        if (priv->RFChangeInProgress) {
  63                spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
  64                RT_TRACE(COMP_DBG,
  65                         "rtl92e_hw_wakeup(): RF Change in progress!\n");
  66                schedule_delayed_work(&priv->rtllib->hw_wakeup_wq,
  67                                      msecs_to_jiffies(10));
  68                return;
  69        }
  70        spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
  71        RT_TRACE(COMP_PS, "%s()============>come to wake up\n", __func__);
  72        rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_PS);
  73}
  74
  75void rtl92e_hw_wakeup_wq(void *data)
  76{
  77        struct rtllib_device *ieee = container_of_dwork_rsl(data,
  78                                     struct rtllib_device, hw_wakeup_wq);
  79        struct net_device *dev = ieee->dev;
  80
  81        rtl92e_hw_wakeup(dev);
  82}
  83
  84#define MIN_SLEEP_TIME 50
  85#define MAX_SLEEP_TIME 10000
  86void rtl92e_enter_sleep(struct net_device *dev, u64 time)
  87{
  88        struct r8192_priv *priv = rtllib_priv(dev);
  89
  90        u32 tmp;
  91        unsigned long flags;
  92        unsigned long timeout;
  93
  94        spin_lock_irqsave(&priv->ps_lock, flags);
  95
  96        time -= msecs_to_jiffies(8 + 16 + 7);
  97
  98        timeout = jiffies + msecs_to_jiffies(MIN_SLEEP_TIME);
  99        if (time_before((unsigned long)time, timeout)) {
 100                spin_unlock_irqrestore(&priv->ps_lock, flags);
 101                netdev_info(dev, "too short to sleep::%lld < %ld\n",
 102                            time - jiffies, msecs_to_jiffies(MIN_SLEEP_TIME));
 103                return;
 104        }
 105        timeout = jiffies + msecs_to_jiffies(MAX_SLEEP_TIME);
 106        if (time_after((unsigned long)time, timeout)) {
 107                netdev_info(dev, "========>too long to sleep:%lld > %ld\n",
 108                            time - jiffies, msecs_to_jiffies(MAX_SLEEP_TIME));
 109                spin_unlock_irqrestore(&priv->ps_lock, flags);
 110                return;
 111        }
 112        tmp = time - jiffies;
 113        schedule_delayed_work(&priv->rtllib->hw_wakeup_wq, tmp);
 114        schedule_delayed_work(&priv->rtllib->hw_sleep_wq, 0);
 115        spin_unlock_irqrestore(&priv->ps_lock, flags);
 116}
 117
 118static void _rtl92e_ps_update_rf_state(struct net_device *dev)
 119{
 120        struct r8192_priv *priv = rtllib_priv(dev);
 121        struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
 122                                        &(priv->rtllib->PowerSaveControl);
 123
 124        RT_TRACE(COMP_PS, "_rtl92e_ps_update_rf_state() --------->\n");
 125        pPSC->bSwRfProcessing = true;
 126
 127        RT_TRACE(COMP_PS, "_rtl92e_ps_update_rf_state(): Set RF to %s.\n",
 128                 pPSC->eInactivePowerState == eRfOff ? "OFF" : "ON");
 129        rtl92e_set_rf_state(dev, pPSC->eInactivePowerState, RF_CHANGE_BY_IPS);
 130
 131        pPSC->bSwRfProcessing = false;
 132        RT_TRACE(COMP_PS, "_rtl92e_ps_update_rf_state() <---------\n");
 133}
 134
 135void rtl92e_ips_enter(struct net_device *dev)
 136{
 137        struct r8192_priv *priv = rtllib_priv(dev);
 138        struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
 139                                        &(priv->rtllib->PowerSaveControl);
 140        enum rt_rf_power_state rtState;
 141
 142        if (pPSC->bInactivePs) {
 143                rtState = priv->rtllib->eRFPowerState;
 144                if (rtState == eRfOn && !pPSC->bSwRfProcessing &&
 145                        (priv->rtllib->state != RTLLIB_LINKED) &&
 146                        (priv->rtllib->iw_mode != IW_MODE_MASTER)) {
 147                        RT_TRACE(COMP_PS, "rtl92e_ips_enter(): Turn off RF.\n");
 148                        pPSC->eInactivePowerState = eRfOff;
 149                        priv->isRFOff = true;
 150                        priv->bInPowerSaveMode = true;
 151                        _rtl92e_ps_update_rf_state(dev);
 152                }
 153        }
 154}
 155
 156void rtl92e_ips_leave(struct net_device *dev)
 157{
 158        struct r8192_priv *priv = rtllib_priv(dev);
 159        struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
 160                                        &(priv->rtllib->PowerSaveControl);
 161        enum rt_rf_power_state rtState;
 162
 163        if (pPSC->bInactivePs) {
 164                rtState = priv->rtllib->eRFPowerState;
 165                if (rtState != eRfOn  && !pPSC->bSwRfProcessing &&
 166                    priv->rtllib->RfOffReason <= RF_CHANGE_BY_IPS) {
 167                        RT_TRACE(COMP_PS, "rtl92e_ips_leave(): Turn on RF.\n");
 168                        pPSC->eInactivePowerState = eRfOn;
 169                        priv->bInPowerSaveMode = false;
 170                        _rtl92e_ps_update_rf_state(dev);
 171                }
 172        }
 173}
 174
 175void rtl92e_ips_leave_wq(void *data)
 176{
 177        struct rtllib_device *ieee = container_of_work_rsl(data,
 178                                     struct rtllib_device, ips_leave_wq);
 179        struct net_device *dev = ieee->dev;
 180        struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
 181
 182        mutex_lock(&priv->rtllib->ips_mutex);
 183        rtl92e_ips_leave(dev);
 184        mutex_unlock(&priv->rtllib->ips_mutex);
 185}
 186
 187void rtl92e_rtllib_ips_leave_wq(struct net_device *dev)
 188{
 189        struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
 190        enum rt_rf_power_state rtState;
 191
 192        rtState = priv->rtllib->eRFPowerState;
 193
 194        if (priv->rtllib->PowerSaveControl.bInactivePs) {
 195                if (rtState == eRfOff) {
 196                        if (priv->rtllib->RfOffReason > RF_CHANGE_BY_IPS) {
 197                                netdev_warn(dev, "%s(): RF is OFF.\n",
 198                                            __func__);
 199                                return;
 200                        }
 201                        netdev_info(dev, "=========>%s(): rtl92e_ips_leave\n",
 202                                    __func__);
 203                        schedule_work(&priv->rtllib->ips_leave_wq);
 204                }
 205        }
 206}
 207
 208void rtl92e_rtllib_ips_leave(struct net_device *dev)
 209{
 210        struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
 211
 212        mutex_lock(&priv->rtllib->ips_mutex);
 213        rtl92e_ips_leave(dev);
 214        mutex_unlock(&priv->rtllib->ips_mutex);
 215}
 216
 217static bool _rtl92e_ps_set_mode(struct net_device *dev, u8 rtPsMode)
 218{
 219        struct r8192_priv *priv = rtllib_priv(dev);
 220
 221        if (priv->rtllib->iw_mode == IW_MODE_ADHOC)
 222                return false;
 223
 224        RT_TRACE(COMP_LPS, "%s(): set ieee->ps = %x\n", __func__, rtPsMode);
 225        if (!priv->ps_force)
 226                priv->rtllib->ps = rtPsMode;
 227        if (priv->rtllib->sta_sleep != LPS_IS_WAKE &&
 228            rtPsMode == RTLLIB_PS_DISABLED) {
 229                unsigned long flags;
 230
 231                rtl92e_hw_wakeup(dev);
 232                priv->rtllib->sta_sleep = LPS_IS_WAKE;
 233
 234                spin_lock_irqsave(&(priv->rtllib->mgmt_tx_lock), flags);
 235                RT_TRACE(COMP_DBG,
 236                         "LPS leave: notify AP we are awaked ++++++++++ SendNullFunctionData\n");
 237                rtllib_sta_ps_send_null_frame(priv->rtllib, 0);
 238                spin_unlock_irqrestore(&(priv->rtllib->mgmt_tx_lock), flags);
 239        }
 240
 241        return true;
 242}
 243
 244void rtl92e_leisure_ps_enter(struct net_device *dev)
 245{
 246        struct r8192_priv *priv = rtllib_priv(dev);
 247        struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
 248                                        &(priv->rtllib->PowerSaveControl);
 249
 250        RT_TRACE(COMP_PS, "rtl92e_leisure_ps_enter()...\n");
 251        RT_TRACE(COMP_PS,
 252                 "pPSC->bLeisurePs = %d, ieee->ps = %d,pPSC->LpsIdleCount is %d,RT_CHECK_FOR_HANG_PERIOD is %d\n",
 253                 pPSC->bLeisurePs, priv->rtllib->ps, pPSC->LpsIdleCount,
 254                 RT_CHECK_FOR_HANG_PERIOD);
 255
 256        if (!((priv->rtllib->iw_mode == IW_MODE_INFRA) &&
 257            (priv->rtllib->state == RTLLIB_LINKED))
 258            || (priv->rtllib->iw_mode == IW_MODE_ADHOC) ||
 259            (priv->rtllib->iw_mode == IW_MODE_MASTER))
 260                return;
 261
 262        if (pPSC->bLeisurePs) {
 263                if (pPSC->LpsIdleCount >= RT_CHECK_FOR_HANG_PERIOD) {
 264
 265                        if (priv->rtllib->ps == RTLLIB_PS_DISABLED) {
 266
 267                                RT_TRACE(COMP_LPS,
 268                                         "rtl92e_leisure_ps_enter(): Enter 802.11 power save mode...\n");
 269
 270                                if (!pPSC->bFwCtrlLPS) {
 271                                        if (priv->rtllib->SetFwCmdHandler)
 272                                                priv->rtllib->SetFwCmdHandler(
 273                                                        dev, FW_CMD_LPS_ENTER);
 274                                }
 275                                _rtl92e_ps_set_mode(dev, RTLLIB_PS_MBCAST |
 276                                                         RTLLIB_PS_UNICAST);
 277                        }
 278                } else
 279                        pPSC->LpsIdleCount++;
 280        }
 281}
 282
 283void rtl92e_leisure_ps_leave(struct net_device *dev)
 284{
 285        struct r8192_priv *priv = rtllib_priv(dev);
 286        struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
 287                                        &(priv->rtllib->PowerSaveControl);
 288
 289
 290        RT_TRACE(COMP_PS, "rtl92e_leisure_ps_leave()...\n");
 291        RT_TRACE(COMP_PS, "pPSC->bLeisurePs = %d, ieee->ps = %d\n",
 292                pPSC->bLeisurePs, priv->rtllib->ps);
 293
 294        if (pPSC->bLeisurePs) {
 295                if (priv->rtllib->ps != RTLLIB_PS_DISABLED) {
 296                        RT_TRACE(COMP_LPS,
 297                                 "rtl92e_leisure_ps_leave(): Busy Traffic , Leave 802.11 power save..\n");
 298                        _rtl92e_ps_set_mode(dev, RTLLIB_PS_DISABLED);
 299
 300                        if (!pPSC->bFwCtrlLPS) {
 301                                if (priv->rtllib->SetFwCmdHandler)
 302                                        priv->rtllib->SetFwCmdHandler(dev,
 303                                                         FW_CMD_LPS_LEAVE);
 304                    }
 305                }
 306        }
 307}
 308