linux/drivers/staging/rtl8723au/core/rtw_pwrctrl.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of version 2 of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12 * more details.
  13 *
  14 ******************************************************************************/
  15#define _RTW_PWRCTRL_C_
  16
  17#include <osdep_service.h>
  18#include <drv_types.h>
  19#include <osdep_intf.h>
  20
  21#ifdef CONFIG_8723AU_BT_COEXIST
  22#include <rtl8723a_hal.h>
  23#endif
  24
  25void ips_enter23a(struct rtw_adapter * padapter)
  26{
  27        struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
  28
  29        down(&pwrpriv->lock);
  30
  31        pwrpriv->bips_processing = true;
  32
  33        /*  syn ips_mode with request */
  34        pwrpriv->ips_mode = pwrpriv->ips_mode_req;
  35
  36        pwrpriv->ips_enter23a_cnts++;
  37        DBG_8723A("==>ips_enter23a cnts:%d\n", pwrpriv->ips_enter23a_cnts);
  38#ifdef CONFIG_8723AU_BT_COEXIST
  39        BTDM_TurnOffBtCoexistBeforeEnterIPS(padapter);
  40#endif
  41        if (rf_off == pwrpriv->change_rfpwrstate)
  42        {
  43                pwrpriv->bpower_saving = true;
  44                DBG_8723A_LEVEL(_drv_always_, "nolinked power save enter\n");
  45
  46                if (pwrpriv->ips_mode == IPS_LEVEL_2)
  47                        pwrpriv->bkeepfwalive = true;
  48
  49                rtw_ips_pwr_down23a(padapter);
  50                pwrpriv->rf_pwrstate = rf_off;
  51        }
  52        pwrpriv->bips_processing = false;
  53
  54        up(&pwrpriv->lock);
  55}
  56
  57int ips_leave23a(struct rtw_adapter * padapter)
  58{
  59        struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
  60        struct security_priv *psecuritypriv = &padapter->securitypriv;
  61        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
  62        int result = _SUCCESS;
  63        int keyid;
  64
  65        down(&pwrpriv->lock);
  66
  67        if ((pwrpriv->rf_pwrstate == rf_off) &&!pwrpriv->bips_processing)
  68        {
  69                pwrpriv->bips_processing = true;
  70                pwrpriv->change_rfpwrstate = rf_on;
  71                pwrpriv->ips_leave23a_cnts++;
  72                DBG_8723A("==>ips_leave23a cnts:%d\n", pwrpriv->ips_leave23a_cnts);
  73
  74                if ((result = rtw_ips_pwr_up23a(padapter)) == _SUCCESS) {
  75                        pwrpriv->rf_pwrstate = rf_on;
  76                }
  77                DBG_8723A_LEVEL(_drv_always_, "nolinked power save leave\n");
  78
  79                if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) ||(_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm))
  80                {
  81                        DBG_8723A("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing);
  82                        set_channel_bwmode23a(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
  83                        for (keyid = 0;keyid<4;keyid++) {
  84                                if (pmlmepriv->key_mask & CHKBIT(keyid)) {
  85                                        if (keyid == psecuritypriv->dot11PrivacyKeyIndex)
  86                                                result = rtw_set_key23a(padapter, psecuritypriv, keyid, 1);
  87                                        else
  88                                                result = rtw_set_key23a(padapter, psecuritypriv, keyid, 0);
  89                                }
  90                        }
  91                }
  92
  93                DBG_8723A("==> ips_leave23a.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c));
  94                pwrpriv->bips_processing = false;
  95
  96                pwrpriv->bkeepfwalive = false;
  97                pwrpriv->bpower_saving = false;
  98        }
  99
 100        up(&pwrpriv->lock);
 101
 102        return result;
 103}
 104
 105
 106static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter)
 107{
 108        struct rtw_adapter *buddy = adapter->pbuddy_adapter;
 109        struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
 110        struct xmit_priv *pxmit_priv = &adapter->xmitpriv;
 111        struct wifidirect_info *pwdinfo = &adapter->wdinfo;
 112
 113        bool ret = false;
 114
 115        if (time_after_eq(adapter->pwrctrlpriv.ips_deny_time, jiffies))
 116                goto exit;
 117
 118        if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
 119                || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
 120                || check_fwstate(pmlmepriv, WIFI_AP_STATE)
 121                || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
 122                || !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
 123        ) {
 124                goto exit;
 125        }
 126
 127        /* consider buddy, if exist */
 128        if (buddy) {
 129                struct mlme_priv *b_pmlmepriv = &buddy->mlmepriv;
 130                struct wifidirect_info *b_pwdinfo = &buddy->wdinfo;
 131
 132                if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
 133                        || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
 134                        || check_fwstate(b_pmlmepriv, WIFI_AP_STATE)
 135                        || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
 136                        || !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE)
 137                ) {
 138                        goto exit;
 139                }
 140        }
 141
 142        if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF ||
 143                pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) {
 144                DBG_8723A_LEVEL(_drv_always_, "There are some pkts to transmit\n");
 145                DBG_8723A_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n",
 146                        pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt);
 147                goto exit;
 148        }
 149
 150        ret = true;
 151
 152exit:
 153        return ret;
 154}
 155
 156void rtw_ps_processor23a(struct rtw_adapter*padapter)
 157{
 158        struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
 159        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 160        enum rt_rf_power_state rfpwrstate;
 161
 162        pwrpriv->ps_processing = true;
 163
 164        if (pwrpriv->bips_processing == true)
 165                goto exit;
 166
 167        if (padapter->pwrctrlpriv.bHWPwrPindetect) {
 168                rfpwrstate = RfOnOffDetect23a(padapter);
 169                DBG_8723A("@@@@- #2  %s ==> rfstate:%s\n", __func__, (rfpwrstate == rf_on)?"rf_on":"rf_off");
 170
 171                if (rfpwrstate!= pwrpriv->rf_pwrstate) {
 172                        if (rfpwrstate == rf_off) {
 173                                pwrpriv->change_rfpwrstate = rf_off;
 174                                pwrpriv->brfoffbyhw = true;
 175                                padapter->bCardDisableWOHSM = true;
 176                                rtw_hw_suspend23a(padapter);
 177                        } else {
 178                                pwrpriv->change_rfpwrstate = rf_on;
 179                                rtw_hw_resume23a(padapter);
 180                        }
 181                        DBG_8723A("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off)?"rf_off":"rf_on");
 182                }
 183                pwrpriv->pwr_state_check_cnts ++;
 184        }
 185
 186        if (pwrpriv->ips_mode_req == IPS_NONE)
 187                goto exit;
 188
 189        if (rtw_pwr_unassociated_idle(padapter) == false)
 190                goto exit;
 191
 192        if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0))
 193        {
 194                DBG_8723A("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv));
 195                pwrpriv->change_rfpwrstate = rf_off;
 196                ips_enter23a(padapter);
 197        }
 198exit:
 199        rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
 200        pwrpriv->ps_processing = false;
 201        return;
 202}
 203
 204static void pwr_state_check_handler(unsigned long data)
 205{
 206        struct rtw_adapter *padapter = (struct rtw_adapter *)data;
 207        rtw_ps_cmd23a(padapter);
 208}
 209
 210/*
 211 *
 212 * Parameters
 213 *      padapter
 214 *      pslv                    power state level, only could be PS_STATE_S0 ~ PS_STATE_S4
 215 *
 216 */
 217void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 pslv)
 218{
 219        u8      rpwm;
 220        struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
 221
 222
 223
 224        pslv = PS_STATE(pslv);
 225
 226        if (true == pwrpriv->btcoex_rfon)
 227        {
 228                if (pslv < PS_STATE_S4)
 229                        pslv = PS_STATE_S3;
 230        }
 231
 232        if (pwrpriv->rpwm == pslv) {
 233                RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
 234                        ("%s: Already set rpwm[0x%02X], new = 0x%02X!\n", __func__, pwrpriv->rpwm, pslv));
 235                return;
 236        }
 237
 238        if ((padapter->bSurpriseRemoved == true) ||
 239            (padapter->hw_init_completed == false)) {
 240                RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
 241                                 ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n",
 242                                  __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed));
 243
 244                pwrpriv->cpwm = PS_STATE_S4;
 245
 246                return;
 247        }
 248
 249        if (padapter->bDriverStopped == true) {
 250                RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
 251                                 ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv));
 252
 253                if (pslv < PS_STATE_S2) {
 254                        RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
 255                                         ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv));
 256                        return;
 257                }
 258        }
 259
 260        rpwm = pslv | pwrpriv->tog;
 261        RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
 262                         ("rtw_set_rpwm23a: rpwm = 0x%02x cpwm = 0x%02x\n", rpwm, pwrpriv->cpwm));
 263
 264        pwrpriv->rpwm = pslv;
 265
 266        rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm));
 267
 268        pwrpriv->tog += 0x80;
 269        pwrpriv->cpwm = pslv;
 270
 271
 272}
 273
 274u8 PS_RDY_CHECK(struct rtw_adapter * padapter)
 275{
 276        unsigned long delta_time;
 277        struct pwrctrl_priv     *pwrpriv = &padapter->pwrctrlpriv;
 278        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 279
 280        delta_time = jiffies - pwrpriv->DelayLPSLastTimeStamp;
 281
 282        if (delta_time < LPS_DELAY_TIME)
 283        {
 284                return false;
 285        }
 286
 287        if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) ||
 288                (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) ||
 289                (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ||
 290                (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
 291                (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
 292                return false;
 293        if (true == pwrpriv->bInSuspend)
 294                return false;
 295        if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false))
 296        {
 297                DBG_8723A("Group handshake still in progress !!!\n");
 298                return false;
 299        }
 300        if (!rtw_cfg80211_pwr_mgmt(padapter))
 301                return false;
 302
 303        return true;
 304}
 305
 306void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode)
 307{
 308        struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
 309#ifdef CONFIG_8723AU_P2P
 310        struct wifidirect_info *pwdinfo = &padapter->wdinfo;
 311#endif /* CONFIG_8723AU_P2P */
 312
 313
 314
 315        RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
 316                         ("%s: PowerMode =%d Smart_PS =%d\n",
 317                          __func__, ps_mode, smart_ps));
 318
 319        if (ps_mode > PM_Card_Disable) {
 320                RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode));
 321                return;
 322        }
 323
 324        if (pwrpriv->pwr_mode == ps_mode)
 325        {
 326                if (PS_MODE_ACTIVE == ps_mode) return;
 327
 328                if ((pwrpriv->smart_ps == smart_ps) &&
 329                        (pwrpriv->bcn_ant_mode == bcn_ant_mode))
 330                {
 331                        return;
 332                }
 333        }
 334
 335        if (ps_mode == PS_MODE_ACTIVE) {
 336#ifdef CONFIG_8723AU_P2P
 337                if (pwdinfo->opp_ps == 0)
 338#endif /* CONFIG_8723AU_P2P */
 339                {
 340                        DBG_8723A("rtw_set_ps_mode23a: Leave 802.11 power save\n");
 341
 342                        pwrpriv->pwr_mode = ps_mode;
 343                        rtw_set_rpwm23a(padapter, PS_STATE_S4);
 344                        rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
 345                        pwrpriv->bFwCurrentInPSMode = false;
 346                }
 347        }
 348        else
 349        {
 350                if (PS_RDY_CHECK(padapter)
 351#ifdef CONFIG_8723AU_BT_COEXIST
 352                        || (BT_1Ant(padapter) == true)
 353#endif
 354                        )
 355                {
 356                        DBG_8723A("%s: Enter 802.11 power save\n", __func__);
 357
 358                        pwrpriv->bFwCurrentInPSMode = true;
 359                        pwrpriv->pwr_mode = ps_mode;
 360                        pwrpriv->smart_ps = smart_ps;
 361                        pwrpriv->bcn_ant_mode = bcn_ant_mode;
 362                        rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
 363
 364#ifdef CONFIG_8723AU_P2P
 365                        /*  Set CTWindow after LPS */
 366                        if (pwdinfo->opp_ps == 1)
 367                                p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 0);
 368#endif /* CONFIG_8723AU_P2P */
 369
 370                        rtw_set_rpwm23a(padapter, PS_STATE_S2);
 371                }
 372        }
 373
 374
 375}
 376
 377/*
 378 * Return:
 379 *      0:      Leave OK
 380 *      -1:     Timeout
 381 *      -2:     Other error
 382 */
 383s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms)
 384{
 385        unsigned long start_time, end_time;
 386        u8 bAwake = false;
 387        s32 err = 0;
 388
 389        start_time = jiffies;
 390        end_time = start_time + msecs_to_jiffies(delay_ms);
 391
 392        while (1)
 393        {
 394                rtw23a_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake);
 395                if (true == bAwake)
 396                        break;
 397
 398                if (true == padapter->bSurpriseRemoved)
 399                {
 400                        err = -2;
 401                        DBG_8723A("%s: device surprise removed!!\n", __func__);
 402                        break;
 403                }
 404
 405                if (time_after(jiffies, end_time)) {
 406                        err = -1;
 407                        DBG_8723A("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms);
 408                        break;
 409                }
 410                udelay(100);
 411        }
 412
 413        return err;
 414}
 415
 416/*      Description: */
 417/*              Enter the leisure power save mode. */
 418void LPS_Enter23a(struct rtw_adapter *padapter)
 419{
 420        struct pwrctrl_priv     *pwrpriv = &padapter->pwrctrlpriv;
 421
 422        if (!PS_RDY_CHECK(padapter))
 423                return;
 424
 425        if (pwrpriv->bLeisurePs) {
 426                /*  Idle for a while if we connect to AP a while ago. */
 427                if (pwrpriv->LpsIdleCount >= 2) { /*   4 Sec */
 428                        if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
 429                                pwrpriv->bpower_saving = true;
 430                                DBG_8723A("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps);
 431                                /* For Tenda W311R IOT issue */
 432                                rtw_set_ps_mode23a(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0);
 433                        }
 434                } else {
 435                        pwrpriv->LpsIdleCount++;
 436                }
 437        }
 438}
 439
 440/*      Description: */
 441/*              Leave the leisure power save mode. */
 442void LPS_Leave23a(struct rtw_adapter *padapter)
 443{
 444#define LPS_LEAVE_TIMEOUT_MS 100
 445
 446        struct pwrctrl_priv     *pwrpriv = &padapter->pwrctrlpriv;
 447
 448        if (pwrpriv->bLeisurePs) {
 449                if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
 450                        rtw_set_ps_mode23a(padapter, PS_MODE_ACTIVE, 0, 0);
 451
 452                        if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
 453                                LPS_RF_ON_check23a(padapter, LPS_LEAVE_TIMEOUT_MS);
 454                }
 455        }
 456
 457        pwrpriv->bpower_saving = false;
 458}
 459
 460/*  Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */
 461/*  Move code to function by tynli. 2010.03.26. */
 462void LeaveAllPowerSaveMode23a(struct rtw_adapter *Adapter)
 463{
 464        struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
 465        u8      enqueue = 0;
 466
 467
 468
 469        /* DBG_8723A("%s.....\n", __func__); */
 470        if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
 471        { /* connect */
 472#ifdef CONFIG_8723AU_P2P
 473                p2p_ps_wk_cmd23a(Adapter, P2P_PS_DISABLE, enqueue);
 474#endif /* CONFIG_8723AU_P2P */
 475
 476                rtw_lps_ctrl_wk_cmd23a(Adapter, LPS_CTRL_LEAVE, enqueue);
 477        }
 478
 479
 480}
 481
 482void rtw_init_pwrctrl_priv23a(struct rtw_adapter *padapter)
 483{
 484        struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
 485
 486        sema_init(&pwrctrlpriv->lock, 1);
 487        pwrctrlpriv->rf_pwrstate = rf_on;
 488        pwrctrlpriv->ips_enter23a_cnts = 0;
 489        pwrctrlpriv->ips_leave23a_cnts = 0;
 490        pwrctrlpriv->bips_processing = false;
 491
 492        pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode;
 493        pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode;
 494
 495        pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL;
 496        pwrctrlpriv->pwr_state_check_cnts = 0;
 497        pwrctrlpriv->bInternalAutoSuspend = false;
 498        pwrctrlpriv->bInSuspend = false;
 499        pwrctrlpriv->bkeepfwalive = false;
 500
 501        pwrctrlpriv->LpsIdleCount = 0;
 502        pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/*  PS_MODE_MIN; */
 503        pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false;
 504
 505        pwrctrlpriv->bFwCurrentInPSMode = false;
 506
 507        pwrctrlpriv->rpwm = 0;
 508        pwrctrlpriv->cpwm = PS_STATE_S4;
 509
 510        pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
 511        pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps;
 512        pwrctrlpriv->bcn_ant_mode = 0;
 513
 514        pwrctrlpriv->tog = 0x80;
 515
 516        pwrctrlpriv->btcoex_rfon = false;
 517
 518        setup_timer(&pwrctrlpriv->pwr_state_check_timer,
 519                    pwr_state_check_handler, (unsigned long)padapter);
 520
 521
 522}
 523
 524void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter)
 525{
 526}
 527
 528u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8* val)
 529{
 530        u8 bResult = true;
 531        rtw_hal_intf_ps_func23a(padapter, efunc_id, val);
 532
 533        return bResult;
 534}
 535
 536inline void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms)
 537{
 538        struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
 539        pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ms);
 540}
 541
 542/*
 543* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
 544* @adapter: pointer to _adapter structure
 545* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup
 546* Return _SUCCESS or _FAIL
 547*/
 548
 549int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const char *caller)
 550{
 551        struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
 552        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
 553        int ret = _SUCCESS;
 554        unsigned long start = jiffies;
 555        unsigned long new_deny_time;
 556
 557        new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms);
 558
 559        if (time_before(pwrpriv->ips_deny_time, new_deny_time))
 560                pwrpriv->ips_deny_time = new_deny_time;
 561
 562        if (pwrpriv->ps_processing) {
 563                DBG_8723A("%s wait ps_processing...\n", __func__);
 564                while (pwrpriv->ps_processing &&
 565                       jiffies_to_msecs(jiffies - start) <= 3000)
 566                        msleep(10);
 567                if (pwrpriv->ps_processing)
 568                        DBG_8723A("%s wait ps_processing timeout\n", __func__);
 569                else
 570                        DBG_8723A("%s wait ps_processing done\n", __func__);
 571        }
 572
 573        if (rtw_hal_sreset_inprogress(padapter)) {
 574                DBG_8723A("%s wait sreset_inprogress...\n", __func__);
 575                while (rtw_hal_sreset_inprogress(padapter) &&
 576                       jiffies_to_msecs(jiffies - start) <= 4000)
 577                        msleep(10);
 578                if (rtw_hal_sreset_inprogress(padapter))
 579                        DBG_8723A("%s wait sreset_inprogress timeout\n", __func__);
 580                else
 581                        DBG_8723A("%s wait sreset_inprogress done\n", __func__);
 582        }
 583
 584        if (pwrpriv->bInternalAutoSuspend == false && pwrpriv->bInSuspend) {
 585                DBG_8723A("%s wait bInSuspend...\n", __func__);
 586                while (pwrpriv->bInSuspend &&
 587                       (jiffies_to_msecs(jiffies - start) <= 3000)) {
 588                        msleep(10);
 589                }
 590                if (pwrpriv->bInSuspend)
 591                        DBG_8723A("%s wait bInSuspend timeout\n", __func__);
 592                else
 593                        DBG_8723A("%s wait bInSuspend done\n", __func__);
 594        }
 595
 596        /* System suspend is not allowed to wakeup */
 597        if ((pwrpriv->bInternalAutoSuspend == false) && (true == pwrpriv->bInSuspend)) {
 598                ret = _FAIL;
 599                goto exit;
 600        }
 601
 602        /* block??? */
 603        if ((pwrpriv->bInternalAutoSuspend == true)  && (padapter->net_closed == true)) {
 604                ret = _FAIL;
 605                goto exit;
 606        }
 607
 608        /* I think this should be check in IPS, LPS, autosuspend functions... */
 609        if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
 610        {
 611                ret = _SUCCESS;
 612                goto exit;
 613        }
 614
 615        if (rf_off == pwrpriv->rf_pwrstate) {
 616                DBG_8723A("%s call ips_leave23a....\n", __func__);
 617                if (_FAIL ==  ips_leave23a(padapter)) {
 618                        DBG_8723A("======> ips_leave23a fail.............\n");
 619                        ret = _FAIL;
 620                        goto exit;
 621                }
 622        }
 623
 624        /* TODO: the following checking need to be merged... */
 625        if (padapter->bDriverStopped || !padapter->bup ||
 626            !padapter->hw_init_completed) {
 627                DBG_8723A("%s: bDriverStopped =%d, bup =%d, hw_init_completed "
 628                          "=%u\n", caller, padapter->bDriverStopped,
 629                          padapter->bup, padapter->hw_init_completed);
 630                ret = false;
 631                goto exit;
 632        }
 633
 634exit:
 635        new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms);
 636        if (time_before(pwrpriv->ips_deny_time, new_deny_time))
 637                pwrpriv->ips_deny_time = new_deny_time;
 638        return ret;
 639}
 640
 641int rtw_pm_set_lps23a(struct rtw_adapter *padapter, u8 mode)
 642{
 643        int     ret = 0;
 644        struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
 645
 646        if (mode < PS_MODE_NUM)
 647        {
 648                if (pwrctrlpriv->power_mgnt != mode)
 649                {
 650                        if (PS_MODE_ACTIVE == mode)
 651                        {
 652                                LeaveAllPowerSaveMode23a(padapter);
 653                        }
 654                        else
 655                        {
 656                                pwrctrlpriv->LpsIdleCount = 2;
 657                        }
 658                        pwrctrlpriv->power_mgnt = mode;
 659                        pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false;
 660                }
 661        }
 662        else
 663        {
 664                ret = -EINVAL;
 665        }
 666
 667        return ret;
 668}
 669
 670int rtw_pm_set_ips23a(struct rtw_adapter *padapter, u8 mode)
 671{
 672        struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
 673
 674        if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) {
 675                rtw_ips_mode_req(pwrctrlpriv, mode);
 676                DBG_8723A("%s %s\n", __func__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2");
 677                return 0;
 678        }
 679        else if (mode == IPS_NONE) {
 680                rtw_ips_mode_req(pwrctrlpriv, mode);
 681                DBG_8723A("%s %s\n", __func__, "IPS_NONE");
 682                if ((padapter->bSurpriseRemoved == 0)&&_FAIL == rtw_pwr_wakeup(padapter))
 683                        return -EFAULT;
 684        }
 685        else {
 686                return -EINVAL;
 687        }
 688        return 0;
 689}
 690