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