linux/drivers/net/wireless/rtlwifi/ps.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2009-2012  Realtek Corporation.
   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 * The full GNU General Public License is included in this distribution in the
  15 * file called LICENSE.
  16 *
  17 * Contact Information:
  18 * wlanfae <wlanfae@realtek.com>
  19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  20 * Hsinchu 300, Taiwan.
  21 *
  22 * Larry Finger <Larry.Finger@lwfinger.net>
  23 *
  24 *****************************************************************************/
  25
  26#include "wifi.h"
  27#include "base.h"
  28#include "ps.h"
  29#include <linux/export.h>
  30#include "btcoexist/rtl_btc.h"
  31
  32bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
  33{
  34        struct rtl_priv *rtlpriv = rtl_priv(hw);
  35        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
  36        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
  37
  38        /*<1> reset trx ring */
  39        if (rtlhal->interface == INTF_PCI)
  40                rtlpriv->intf_ops->reset_trx_ring(hw);
  41
  42        if (is_hal_stop(rtlhal))
  43                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
  44                         "Driver is already down!\n");
  45
  46        /*<2> Enable Adapter */
  47        if (rtlpriv->cfg->ops->hw_init(hw))
  48                return false;
  49        RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
  50
  51        /*<3> Enable Interrupt */
  52        rtlpriv->cfg->ops->enable_interrupt(hw);
  53
  54        /*<enable timer> */
  55        rtl_watch_dog_timer_callback((unsigned long)hw);
  56
  57        return true;
  58}
  59EXPORT_SYMBOL(rtl_ps_enable_nic);
  60
  61bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
  62{
  63        struct rtl_priv *rtlpriv = rtl_priv(hw);
  64
  65        /*<1> Stop all timer */
  66        rtl_deinit_deferred_work(hw);
  67
  68        /*<2> Disable Interrupt */
  69        rtlpriv->cfg->ops->disable_interrupt(hw);
  70        tasklet_kill(&rtlpriv->works.irq_tasklet);
  71
  72        /*<3> Disable Adapter */
  73        rtlpriv->cfg->ops->hw_disable(hw);
  74
  75        return true;
  76}
  77EXPORT_SYMBOL(rtl_ps_disable_nic);
  78
  79bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
  80                         enum rf_pwrstate state_toset,
  81                         u32 changesource, bool protect_or_not)
  82{
  83        struct rtl_priv *rtlpriv = rtl_priv(hw);
  84        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
  85        enum rf_pwrstate rtstate;
  86        bool actionallowed = false;
  87        u16 rfwait_cnt = 0;
  88
  89        if (protect_or_not)
  90                goto no_protect;
  91
  92        /*Only one thread can change
  93         *the RF state at one time, and others
  94         *should wait to be executed.
  95         */
  96        while (true) {
  97                spin_lock(&rtlpriv->locks.rf_ps_lock);
  98                if (ppsc->rfchange_inprogress) {
  99                        spin_unlock(&rtlpriv->locks.rf_ps_lock);
 100
 101                        RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 102                                 "RF Change in progress! Wait to set..state_toset(%d).\n",
 103                                  state_toset);
 104
 105                        /* Set RF after the previous action is done.  */
 106                        while (ppsc->rfchange_inprogress) {
 107                                rfwait_cnt++;
 108                                mdelay(1);
 109                                /*Wait too long, return false to avoid
 110                                 *to be stuck here.
 111                                 */
 112                                if (rfwait_cnt > 100)
 113                                        return false;
 114                        }
 115                } else {
 116                        ppsc->rfchange_inprogress = true;
 117                        spin_unlock(&rtlpriv->locks.rf_ps_lock);
 118                        break;
 119                }
 120        }
 121
 122no_protect:
 123        rtstate = ppsc->rfpwr_state;
 124
 125        switch (state_toset) {
 126        case ERFON:
 127                ppsc->rfoff_reason &= (~changesource);
 128
 129                if ((changesource == RF_CHANGE_BY_HW) &&
 130                    (ppsc->hwradiooff)) {
 131                        ppsc->hwradiooff = false;
 132                }
 133
 134                if (!ppsc->rfoff_reason) {
 135                        ppsc->rfoff_reason = 0;
 136                        actionallowed = true;
 137                }
 138
 139                break;
 140
 141        case ERFOFF:
 142
 143                if ((changesource == RF_CHANGE_BY_HW) && !ppsc->hwradiooff) {
 144                        ppsc->hwradiooff = true;
 145                }
 146
 147                ppsc->rfoff_reason |= changesource;
 148                actionallowed = true;
 149                break;
 150
 151        case ERFSLEEP:
 152                ppsc->rfoff_reason |= changesource;
 153                actionallowed = true;
 154                break;
 155
 156        default:
 157                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 158                         "switch case not processed\n");
 159                break;
 160        }
 161
 162        if (actionallowed)
 163                rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
 164
 165        if (!protect_or_not) {
 166                spin_lock(&rtlpriv->locks.rf_ps_lock);
 167                ppsc->rfchange_inprogress = false;
 168                spin_unlock(&rtlpriv->locks.rf_ps_lock);
 169        }
 170
 171        return actionallowed;
 172}
 173EXPORT_SYMBOL(rtl_ps_set_rf_state);
 174
 175static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
 176{
 177        struct rtl_priv *rtlpriv = rtl_priv(hw);
 178        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 179        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 180
 181        ppsc->swrf_processing = true;
 182
 183        if (ppsc->inactive_pwrstate == ERFON &&
 184            rtlhal->interface == INTF_PCI) {
 185                if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
 186                    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
 187                    rtlhal->interface == INTF_PCI) {
 188                        rtlpriv->intf_ops->disable_aspm(hw);
 189                        RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 190                }
 191        }
 192
 193        rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
 194                            RF_CHANGE_BY_IPS, false);
 195
 196        if (ppsc->inactive_pwrstate == ERFOFF &&
 197            rtlhal->interface == INTF_PCI) {
 198                if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
 199                    !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
 200                        rtlpriv->intf_ops->enable_aspm(hw);
 201                        RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 202                }
 203        }
 204
 205        ppsc->swrf_processing = false;
 206}
 207
 208void rtl_ips_nic_off_wq_callback(void *data)
 209{
 210        struct rtl_works *rtlworks =
 211            container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
 212        struct ieee80211_hw *hw = rtlworks->hw;
 213        struct rtl_priv *rtlpriv = rtl_priv(hw);
 214        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 215        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 216        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 217        enum rf_pwrstate rtstate;
 218
 219        if (mac->opmode != NL80211_IFTYPE_STATION) {
 220                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 221                         "not station return\n");
 222                return;
 223        }
 224
 225        if (mac->p2p_in_use)
 226                return;
 227
 228        if (mac->link_state > MAC80211_NOLINK)
 229                return;
 230
 231        if (is_hal_stop(rtlhal))
 232                return;
 233
 234        if (rtlpriv->sec.being_setkey)
 235                return;
 236
 237        if (rtlpriv->cfg->ops->bt_coex_off_before_lps)
 238                rtlpriv->cfg->ops->bt_coex_off_before_lps(hw);
 239
 240        if (ppsc->inactiveps) {
 241                rtstate = ppsc->rfpwr_state;
 242
 243                /*
 244                 *Do not enter IPS in the following conditions:
 245                 *(1) RF is already OFF or Sleep
 246                 *(2) swrf_processing (indicates the IPS is still under going)
 247                 *(3) Connectted (only disconnected can trigger IPS)
 248                 *(4) IBSS (send Beacon)
 249                 *(5) AP mode (send Beacon)
 250                 *(6) monitor mode (rcv packet)
 251                 */
 252
 253                if (rtstate == ERFON &&
 254                    !ppsc->swrf_processing &&
 255                    (mac->link_state == MAC80211_NOLINK) &&
 256                    !mac->act_scanning) {
 257                        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 258                                 "IPSEnter(): Turn off RF\n");
 259
 260                        ppsc->inactive_pwrstate = ERFOFF;
 261                        ppsc->in_powersavemode = true;
 262
 263                        /* call before RF off */
 264                        if (rtlpriv->cfg->ops->get_btc_status())
 265                                rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
 266                                                                        ppsc->inactive_pwrstate);
 267
 268                        /*rtl_pci_reset_trx_ring(hw); */
 269                        _rtl_ps_inactive_ps(hw);
 270                }
 271        }
 272}
 273
 274void rtl_ips_nic_off(struct ieee80211_hw *hw)
 275{
 276        struct rtl_priv *rtlpriv = rtl_priv(hw);
 277
 278        /* because when link with ap, mac80211 will ask us
 279         * to disable nic quickly after scan before linking,
 280         * this will cause link failed, so we delay 100ms here
 281         */
 282        queue_delayed_work(rtlpriv->works.rtl_wq,
 283                           &rtlpriv->works.ips_nic_off_wq, MSECS(100));
 284}
 285
 286/* NOTICE: any opmode should exc nic_on, or disable without
 287 * nic_on may something wrong, like adhoc TP
 288 */
 289void rtl_ips_nic_on(struct ieee80211_hw *hw)
 290{
 291        struct rtl_priv *rtlpriv = rtl_priv(hw);
 292        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 293        enum rf_pwrstate rtstate;
 294
 295        cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
 296
 297        spin_lock(&rtlpriv->locks.ips_lock);
 298        if (ppsc->inactiveps) {
 299                rtstate = ppsc->rfpwr_state;
 300
 301                if (rtstate != ERFON &&
 302                    !ppsc->swrf_processing &&
 303                    ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
 304
 305                        ppsc->inactive_pwrstate = ERFON;
 306                        ppsc->in_powersavemode = false;
 307                        _rtl_ps_inactive_ps(hw);
 308                        /* call after RF on */
 309                        if (rtlpriv->cfg->ops->get_btc_status())
 310                                rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
 311                                                                        ppsc->inactive_pwrstate);
 312                }
 313        }
 314        spin_unlock(&rtlpriv->locks.ips_lock);
 315}
 316EXPORT_SYMBOL_GPL(rtl_ips_nic_on);
 317
 318/*for FW LPS*/
 319
 320/*
 321 *Determine if we can set Fw into PS mode
 322 *in current condition.Return TRUE if it
 323 *can enter PS mode.
 324 */
 325static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
 326{
 327        struct rtl_priv *rtlpriv = rtl_priv(hw);
 328        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 329        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 330        u32 ps_timediff;
 331
 332        ps_timediff = jiffies_to_msecs(jiffies -
 333                                       ppsc->last_delaylps_stamp_jiffies);
 334
 335        if (ps_timediff < 2000) {
 336                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 337                         "Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n");
 338                return false;
 339        }
 340
 341        if (mac->link_state != MAC80211_LINKED)
 342                return false;
 343
 344        if (mac->opmode == NL80211_IFTYPE_ADHOC)
 345                return false;
 346
 347        return true;
 348}
 349
 350/* Change current and default preamble mode.*/
 351void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
 352{
 353        struct rtl_priv *rtlpriv = rtl_priv(hw);
 354        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 355        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 356        bool enter_fwlps;
 357
 358        if (mac->opmode == NL80211_IFTYPE_ADHOC)
 359                return;
 360
 361        if (mac->link_state != MAC80211_LINKED)
 362                return;
 363
 364        if (ppsc->dot11_psmode == rt_psmode)
 365                return;
 366
 367        /* Update power save mode configured. */
 368        ppsc->dot11_psmode = rt_psmode;
 369
 370        /*
 371         *<FW control LPS>
 372         *1. Enter PS mode
 373         *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
 374         *   cmd to set Fw into PS mode.
 375         *2. Leave PS mode
 376         *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active
 377         *   mode and set RPWM to turn RF on.
 378         */
 379
 380        if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
 381                if (ppsc->dot11_psmode == EACTIVE) {
 382                        RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 383                                 "FW LPS leave ps_mode:%x\n",
 384                                  FW_PS_ACTIVE_MODE);
 385                        enter_fwlps = false;
 386                        ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
 387                        ppsc->smart_ps = 0;
 388                        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION,
 389                                                      (u8 *)(&enter_fwlps));
 390                        if (ppsc->p2p_ps_info.opp_ps)
 391                                rtl_p2p_ps_cmd(hw , P2P_PS_ENABLE);
 392
 393                        if (rtlpriv->cfg->ops->get_btc_status())
 394                                rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
 395                } else {
 396                        if (rtl_get_fwlps_doze(hw)) {
 397                                RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 398                                         "FW LPS enter ps_mode:%x\n",
 399                                         ppsc->fwctrl_psmode);
 400                                if (rtlpriv->cfg->ops->get_btc_status())
 401                                        rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
 402                                enter_fwlps = true;
 403                                ppsc->pwr_mode = ppsc->fwctrl_psmode;
 404                                ppsc->smart_ps = 2;
 405                                rtlpriv->cfg->ops->set_hw_reg(hw,
 406                                                        HW_VAR_FW_LPS_ACTION,
 407                                                        (u8 *)(&enter_fwlps));
 408
 409                        } else {
 410                                /* Reset the power save related parameters. */
 411                                ppsc->dot11_psmode = EACTIVE;
 412                        }
 413                }
 414        }
 415}
 416
 417/*Enter the leisure power save mode.*/
 418void rtl_lps_enter(struct ieee80211_hw *hw)
 419{
 420        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 421        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 422        struct rtl_priv *rtlpriv = rtl_priv(hw);
 423        unsigned long flag;
 424
 425        if (!ppsc->fwctrl_lps)
 426                return;
 427
 428        if (rtlpriv->sec.being_setkey)
 429                return;
 430
 431        if (rtlpriv->link_info.busytraffic)
 432                return;
 433
 434        /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
 435        if (mac->cnt_after_linked < 5)
 436                return;
 437
 438        if (mac->opmode == NL80211_IFTYPE_ADHOC)
 439                return;
 440
 441        if (mac->link_state != MAC80211_LINKED)
 442                return;
 443
 444        spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 445
 446        /* Idle for a while if we connect to AP a while ago. */
 447        if (mac->cnt_after_linked >= 2) {
 448                if (ppsc->dot11_psmode == EACTIVE) {
 449                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 450                                 "Enter 802.11 power save mode...\n");
 451
 452                        rtl_lps_set_psmode(hw, EAUTOPS);
 453                }
 454        }
 455
 456        spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 457}
 458EXPORT_SYMBOL(rtl_lps_enter);
 459
 460/*Leave the leisure power save mode.*/
 461void rtl_lps_leave(struct ieee80211_hw *hw)
 462{
 463        struct rtl_priv *rtlpriv = rtl_priv(hw);
 464        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 465        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 466        unsigned long flag;
 467
 468        spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 469
 470        if (ppsc->fwctrl_lps) {
 471                if (ppsc->dot11_psmode != EACTIVE) {
 472
 473                        /*FIX ME */
 474                        /*rtlpriv->cfg->ops->enable_interrupt(hw); */
 475
 476                        if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
 477                            RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
 478                            rtlhal->interface == INTF_PCI) {
 479                                rtlpriv->intf_ops->disable_aspm(hw);
 480                                RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 481                        }
 482
 483                        RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 484                                 "Busy Traffic,Leave 802.11 power save..\n");
 485
 486                        rtl_lps_set_psmode(hw, EACTIVE);
 487                }
 488        }
 489        spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 490}
 491EXPORT_SYMBOL(rtl_lps_leave);
 492
 493/* For sw LPS*/
 494void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
 495{
 496        struct rtl_priv *rtlpriv = rtl_priv(hw);
 497        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 498        struct ieee80211_hdr *hdr = data;
 499        struct ieee80211_tim_ie *tim_ie;
 500        u8 *tim;
 501        u8 tim_len;
 502        bool u_buffed;
 503        bool m_buffed;
 504
 505        if (mac->opmode != NL80211_IFTYPE_STATION)
 506                return;
 507
 508        if (!rtlpriv->psc.swctrl_lps)
 509                return;
 510
 511        if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
 512                return;
 513
 514        if (!rtlpriv->psc.sw_ps_enabled)
 515                return;
 516
 517        if (rtlpriv->psc.fwctrl_lps)
 518                return;
 519
 520        if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
 521                return;
 522
 523        /* check if this really is a beacon */
 524        if (!ieee80211_is_beacon(hdr->frame_control))
 525                return;
 526
 527        /* min. beacon length + FCS_LEN */
 528        if (len <= 40 + FCS_LEN)
 529                return;
 530
 531        /* and only beacons from the associated BSSID, please */
 532        if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
 533                return;
 534
 535        rtlpriv->psc.last_beacon = jiffies;
 536
 537        tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
 538        if (!tim)
 539                return;
 540
 541        if (tim[1] < sizeof(*tim_ie))
 542                return;
 543
 544        tim_len = tim[1];
 545        tim_ie = (struct ieee80211_tim_ie *) &tim[2];
 546
 547        if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
 548                rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
 549
 550        /* Check whenever the PHY can be turned off again. */
 551
 552        /* 1. What about buffered unicast traffic for our AID? */
 553        u_buffed = ieee80211_check_tim(tim_ie, tim_len,
 554                                       rtlpriv->mac80211.assoc_id);
 555
 556        /* 2. Maybe the AP wants to send multicast/broadcast data? */
 557        m_buffed = tim_ie->bitmap_ctrl & 0x01;
 558        rtlpriv->psc.multi_buffered = m_buffed;
 559
 560        /* unicast will process by mac80211 through
 561         * set ~IEEE80211_CONF_PS, So we just check
 562         * multicast frames here */
 563        if (!m_buffed) {
 564                /* back to low-power land. and delay is
 565                 * prevent null power save frame tx fail */
 566                queue_delayed_work(rtlpriv->works.rtl_wq,
 567                                   &rtlpriv->works.ps_work, MSECS(5));
 568        } else {
 569                RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
 570                         "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed);
 571        }
 572}
 573EXPORT_SYMBOL_GPL(rtl_swlps_beacon);
 574
 575void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
 576{
 577        struct rtl_priv *rtlpriv = rtl_priv(hw);
 578        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 579        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 580        unsigned long flag;
 581
 582        if (!rtlpriv->psc.swctrl_lps)
 583                return;
 584        if (mac->link_state != MAC80211_LINKED)
 585                return;
 586
 587        if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
 588            RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
 589                rtlpriv->intf_ops->disable_aspm(hw);
 590                RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 591        }
 592
 593        spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 594        rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
 595        spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 596}
 597
 598void rtl_swlps_rfon_wq_callback(void *data)
 599{
 600        struct rtl_works *rtlworks =
 601            container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
 602        struct ieee80211_hw *hw = rtlworks->hw;
 603
 604        rtl_swlps_rf_awake(hw);
 605}
 606
 607void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
 608{
 609        struct rtl_priv *rtlpriv = rtl_priv(hw);
 610        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 611        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 612        unsigned long flag;
 613        u8 sleep_intv;
 614
 615        if (!rtlpriv->psc.sw_ps_enabled)
 616                return;
 617
 618        if ((rtlpriv->sec.being_setkey) ||
 619            (mac->opmode == NL80211_IFTYPE_ADHOC))
 620                return;
 621
 622        /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
 623        if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
 624                return;
 625
 626        if (rtlpriv->link_info.busytraffic)
 627                return;
 628
 629        spin_lock(&rtlpriv->locks.rf_ps_lock);
 630        if (rtlpriv->psc.rfchange_inprogress) {
 631                spin_unlock(&rtlpriv->locks.rf_ps_lock);
 632                return;
 633        }
 634        spin_unlock(&rtlpriv->locks.rf_ps_lock);
 635
 636        spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 637        rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false);
 638        spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 639
 640        if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
 641            !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
 642                rtlpriv->intf_ops->enable_aspm(hw);
 643                RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 644        }
 645
 646        /* here is power save alg, when this beacon is DTIM
 647         * we will set sleep time to dtim_period * n;
 648         * when this beacon is not DTIM, we will set sleep
 649         * time to sleep_intv = rtlpriv->psc.dtim_counter or
 650         * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
 651
 652        if (rtlpriv->psc.dtim_counter == 0) {
 653                if (hw->conf.ps_dtim_period == 1)
 654                        sleep_intv = hw->conf.ps_dtim_period * 2;
 655                else
 656                        sleep_intv = hw->conf.ps_dtim_period;
 657        } else {
 658                sleep_intv = rtlpriv->psc.dtim_counter;
 659        }
 660
 661        if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
 662                sleep_intv = MAX_SW_LPS_SLEEP_INTV;
 663
 664        /* this print should always be dtim_conter = 0 &
 665         * sleep  = dtim_period, that meaons, we should
 666         * awake before every dtim */
 667        RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
 668                 "dtim_counter:%x will sleep :%d beacon_intv\n",
 669                  rtlpriv->psc.dtim_counter, sleep_intv);
 670
 671        /* we tested that 40ms is enough for sw & hw sw delay */
 672        queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
 673                        MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
 674}
 675
 676void rtl_lps_change_work_callback(struct work_struct *work)
 677{
 678        struct rtl_works *rtlworks =
 679            container_of(work, struct rtl_works, lps_change_work);
 680        struct ieee80211_hw *hw = rtlworks->hw;
 681        struct rtl_priv *rtlpriv = rtl_priv(hw);
 682
 683        if (rtlpriv->enter_ps)
 684                rtl_lps_enter(hw);
 685        else
 686                rtl_lps_leave(hw);
 687}
 688EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
 689
 690void rtl_swlps_wq_callback(void *data)
 691{
 692        struct rtl_works *rtlworks = container_of_dwork_rtl(data,
 693                                     struct rtl_works,
 694                                     ps_work);
 695        struct ieee80211_hw *hw = rtlworks->hw;
 696        struct rtl_priv *rtlpriv = rtl_priv(hw);
 697        bool ps = false;
 698
 699        ps = (hw->conf.flags & IEEE80211_CONF_PS);
 700
 701        /* we can sleep after ps null send ok */
 702        if (rtlpriv->psc.state_inap) {
 703                rtl_swlps_rf_sleep(hw);
 704
 705                if (rtlpriv->psc.state && !ps) {
 706                        rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies -
 707                                                 rtlpriv->psc.last_action);
 708                }
 709
 710                if (ps)
 711                        rtlpriv->psc.last_slept = jiffies;
 712
 713                rtlpriv->psc.last_action = jiffies;
 714                rtlpriv->psc.state = ps;
 715        }
 716}
 717
 718static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
 719                           unsigned int len)
 720{
 721        struct rtl_priv *rtlpriv = rtl_priv(hw);
 722        struct ieee80211_mgmt *mgmt = data;
 723        struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
 724        u8 *pos, *end, *ie;
 725        u16 noa_len;
 726        static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
 727        u8 noa_num, index , i, noa_index = 0;
 728        bool find_p2p_ie = false , find_p2p_ps_ie = false;
 729        pos = (u8 *)mgmt->u.beacon.variable;
 730        end = data + len;
 731        ie = NULL;
 732
 733        while (pos + 1 < end) {
 734                if (pos + 2 + pos[1] > end)
 735                        return;
 736
 737                if (pos[0] == 221 && pos[1] > 4) {
 738                        if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
 739                                ie = pos + 2+4;
 740                                break;
 741                        }
 742                }
 743                pos += 2 + pos[1];
 744        }
 745
 746        if (ie == NULL)
 747                return;
 748        find_p2p_ie = true;
 749        /*to find noa ie*/
 750        while (ie + 1 < end) {
 751                noa_len = READEF2BYTE((__le16 *)&ie[1]);
 752                if (ie + 3 + ie[1] > end)
 753                        return;
 754
 755                if (ie[0] == 12) {
 756                        find_p2p_ps_ie = true;
 757                        if ((noa_len - 2) % 13 != 0) {
 758                                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 759                                         "P2P notice of absence: invalid length.%d\n",
 760                                         noa_len);
 761                                return;
 762                        } else {
 763                                noa_num = (noa_len - 2) / 13;
 764                        }
 765                        noa_index = ie[3];
 766                        if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
 767                            P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
 768                                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 769                                         "update NOA ie.\n");
 770                                p2pinfo->noa_index = noa_index;
 771                                p2pinfo->opp_ps = (ie[4] >> 7);
 772                                p2pinfo->ctwindow = ie[4] & 0x7F;
 773                                p2pinfo->noa_num = noa_num;
 774                                index = 5;
 775                                for (i = 0; i < noa_num; i++) {
 776                                        p2pinfo->noa_count_type[i] =
 777                                                        READEF1BYTE(ie+index);
 778                                        index += 1;
 779                                        p2pinfo->noa_duration[i] =
 780                                                 READEF4BYTE((__le32 *)ie+index);
 781                                        index += 4;
 782                                        p2pinfo->noa_interval[i] =
 783                                                 READEF4BYTE((__le32 *)ie+index);
 784                                        index += 4;
 785                                        p2pinfo->noa_start_time[i] =
 786                                                 READEF4BYTE((__le32 *)ie+index);
 787                                        index += 4;
 788                                }
 789
 790                                if (p2pinfo->opp_ps == 1) {
 791                                        p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
 792                                        /* Driver should wait LPS entering
 793                                         * CTWindow
 794                                         */
 795                                        if (rtlpriv->psc.fw_current_inpsmode)
 796                                                rtl_p2p_ps_cmd(hw,
 797                                                               P2P_PS_ENABLE);
 798                                } else if (p2pinfo->noa_num > 0) {
 799                                        p2pinfo->p2p_ps_mode = P2P_PS_NOA;
 800                                        rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
 801                                } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
 802                                        rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
 803                                }
 804                        }
 805                        break;
 806                }
 807                ie += 3 + noa_len;
 808        }
 809
 810        if (find_p2p_ie == true) {
 811                if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
 812                    (find_p2p_ps_ie == false))
 813                        rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
 814        }
 815}
 816
 817static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
 818                              unsigned int len)
 819{
 820        struct rtl_priv *rtlpriv = rtl_priv(hw);
 821        struct ieee80211_mgmt *mgmt = data;
 822        struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
 823        u8 noa_num, index , i , noa_index = 0;
 824        u8 *pos, *end, *ie;
 825        u16 noa_len;
 826        static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
 827
 828        pos = (u8 *)&mgmt->u.action.category;
 829        end = data + len;
 830        ie = NULL;
 831
 832        if (pos[0] == 0x7f) {
 833                if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
 834                        ie = pos + 3+4;
 835        }
 836
 837        if (ie == NULL)
 838                return;
 839
 840        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n");
 841        /*to find noa ie*/
 842        while (ie + 1 < end) {
 843                noa_len = READEF2BYTE((__le16 *)&ie[1]);
 844                if (ie + 3 + ie[1] > end)
 845                        return;
 846
 847                if (ie[0] == 12) {
 848                        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n");
 849                        RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
 850                                      ie, noa_len);
 851                        if ((noa_len - 2) % 13 != 0) {
 852                                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 853                                         "P2P notice of absence: invalid length.%d\n",
 854                                         noa_len);
 855                                return;
 856                        } else {
 857                                noa_num = (noa_len - 2) / 13;
 858                        }
 859                        noa_index = ie[3];
 860                        if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
 861                            P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
 862                                p2pinfo->noa_index = noa_index;
 863                                p2pinfo->opp_ps = (ie[4] >> 7);
 864                                p2pinfo->ctwindow = ie[4] & 0x7F;
 865                                p2pinfo->noa_num = noa_num;
 866                                index = 5;
 867                                for (i = 0; i < noa_num; i++) {
 868                                        p2pinfo->noa_count_type[i] =
 869                                                        READEF1BYTE(ie+index);
 870                                        index += 1;
 871                                        p2pinfo->noa_duration[i] =
 872                                                         READEF4BYTE((__le32 *)ie+index);
 873                                        index += 4;
 874                                        p2pinfo->noa_interval[i] =
 875                                                         READEF4BYTE((__le32 *)ie+index);
 876                                        index += 4;
 877                                        p2pinfo->noa_start_time[i] =
 878                                                         READEF4BYTE((__le32 *)ie+index);
 879                                        index += 4;
 880                                }
 881
 882                                if (p2pinfo->opp_ps == 1) {
 883                                        p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
 884                                        /* Driver should wait LPS entering
 885                                         * CTWindow
 886                                         */
 887                                        if (rtlpriv->psc.fw_current_inpsmode)
 888                                                rtl_p2p_ps_cmd(hw,
 889                                                               P2P_PS_ENABLE);
 890                                } else if (p2pinfo->noa_num > 0) {
 891                                        p2pinfo->p2p_ps_mode = P2P_PS_NOA;
 892                                        rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
 893                                } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
 894                                        rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
 895                                }
 896                        }
 897                        break;
 898                }
 899                ie += 3 + noa_len;
 900        }
 901}
 902
 903void rtl_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state)
 904{
 905        struct rtl_priv *rtlpriv = rtl_priv(hw);
 906        struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
 907        struct rtl_p2p_ps_info  *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
 908
 909        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n" , p2p_ps_state);
 910        switch (p2p_ps_state) {
 911        case P2P_PS_DISABLE:
 912                p2pinfo->p2p_ps_state = p2p_ps_state;
 913                rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
 914                                              &p2p_ps_state);
 915                p2pinfo->noa_index = 0;
 916                p2pinfo->ctwindow = 0;
 917                p2pinfo->opp_ps = 0;
 918                p2pinfo->noa_num = 0;
 919                p2pinfo->p2p_ps_mode = P2P_PS_NONE;
 920                if (rtlps->fw_current_inpsmode) {
 921                        if (rtlps->smart_ps == 0) {
 922                                rtlps->smart_ps = 2;
 923                                rtlpriv->cfg->ops->set_hw_reg(hw,
 924                                         HW_VAR_H2C_FW_PWRMODE,
 925                                         &rtlps->pwr_mode);
 926                        }
 927
 928                }
 929                break;
 930        case P2P_PS_ENABLE:
 931                if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
 932                        p2pinfo->p2p_ps_state = p2p_ps_state;
 933
 934                        if (p2pinfo->ctwindow > 0) {
 935                                if (rtlps->smart_ps != 0) {
 936                                        rtlps->smart_ps = 0;
 937                                        rtlpriv->cfg->ops->set_hw_reg(hw,
 938                                                 HW_VAR_H2C_FW_PWRMODE,
 939                                                 &rtlps->pwr_mode);
 940                                }
 941                        }
 942                        rtlpriv->cfg->ops->set_hw_reg(hw,
 943                                 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
 944                                 &p2p_ps_state);
 945
 946                }
 947                break;
 948        case P2P_PS_SCAN:
 949        case P2P_PS_SCAN_DONE:
 950        case P2P_PS_ALLSTASLEEP:
 951                if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
 952                        p2pinfo->p2p_ps_state = p2p_ps_state;
 953                        rtlpriv->cfg->ops->set_hw_reg(hw,
 954                                 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
 955                                 &p2p_ps_state);
 956                }
 957                break;
 958        default:
 959                break;
 960        }
 961        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 962                 "ctwindow %x oppps %x\n",
 963                 p2pinfo->ctwindow , p2pinfo->opp_ps);
 964        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 965                 "count %x duration %x index %x interval %x start time %x noa num %x\n",
 966                 p2pinfo->noa_count_type[0],
 967                 p2pinfo->noa_duration[0],
 968                 p2pinfo->noa_index,
 969                 p2pinfo->noa_interval[0],
 970                 p2pinfo->noa_start_time[0],
 971                 p2pinfo->noa_num);
 972        RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n");
 973}
 974
 975void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
 976{
 977        struct rtl_priv *rtlpriv = rtl_priv(hw);
 978        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 979        struct ieee80211_hdr *hdr = data;
 980
 981        if (!mac->p2p)
 982                return;
 983        if (mac->link_state != MAC80211_LINKED)
 984                return;
 985        /* min. beacon length + FCS_LEN */
 986        if (len <= 40 + FCS_LEN)
 987                return;
 988
 989        /* and only beacons from the associated BSSID, please */
 990        if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
 991                return;
 992
 993        /* check if this really is a beacon */
 994        if (!(ieee80211_is_beacon(hdr->frame_control) ||
 995              ieee80211_is_probe_resp(hdr->frame_control) ||
 996              ieee80211_is_action(hdr->frame_control)))
 997                return;
 998
 999        if (ieee80211_is_action(hdr->frame_control))
1000                rtl_p2p_action_ie(hw , data , len - FCS_LEN);
1001        else
1002                rtl_p2p_noa_ie(hw , data , len - FCS_LEN);
1003}
1004EXPORT_SYMBOL_GPL(rtl_p2p_info);
1005