1 /******************************************************************************
3 * Copyright(c) 2009-2010 Realtek Corporation.
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.
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
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
21 * Contact Information:
22 * wlanfae <wlanfae@realtek.com>
23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24 * Hsinchu 300, Taiwan.
26 * Larry Finger <Larry.Finger@lwfinger.net>
28 *****************************************************************************/
33 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0))
34 #include <linux/export.h>
36 #include "btcoexist/rtl_btc.h"
38 bool rtl_ps_enable_nic(struct ieee80211_hw
*hw
)
40 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
41 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
42 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
43 bool init_status
= true;
45 /*<1> reset trx ring */
46 if (rtlhal
->interface
== INTF_PCI
)
47 rtlpriv
->intf_ops
->reset_trx_ring(hw
);
49 if (is_hal_stop(rtlhal
))
50 RT_TRACE(COMP_ERR
, DBG_WARNING
, ("Driver is already down!\n"));
52 /*<2> Enable Adapter */
53 rtlpriv
->cfg
->ops
->hw_init(hw
);
54 RT_CLEAR_PS_LEVEL(ppsc
, RT_RF_OFF_LEVL_HALT_NIC
);
55 /*init_status = false; */
57 /*<3> Enable Interrupt */
58 rtlpriv
->cfg
->ops
->enable_interrupt(hw
);
61 rtl_watch_dog_timer_callback((unsigned long)hw
);
65 //EXPORT_SYMBOL(rtl_ps_enable_nic);
67 bool rtl_ps_disable_nic(struct ieee80211_hw
*hw
)
70 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
72 /*<1> Stop all timer */
73 rtl_deinit_deferred_work(hw
);
75 /*<2> Disable Interrupt */
76 rtlpriv
->cfg
->ops
->disable_interrupt(hw
);
78 /*<3> Disable Adapter */
79 rtlpriv
->cfg
->ops
->hw_disable(hw
);
83 //EXPORT_SYMBOL(rtl_ps_disable_nic);
85 bool rtl_ps_set_rf_state(struct ieee80211_hw
*hw
,
86 enum rf_pwrstate state_toset
,
87 u32 changesource
, bool protect_or_not
)
89 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
90 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
91 enum rf_pwrstate rtstate
;
92 bool b_actionallowed
= false;
95 /*protect_or_not = true; */
101 *Only one thread can change
102 *the RF state at one time, and others
103 *should wait to be executed.
106 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
107 if (ppsc
->rfchange_inprogress
) {
108 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
110 RT_TRACE(COMP_ERR
, DBG_WARNING
,
111 ("RF Change in progress!"
112 "Wait to set..state_toset(%d).\n",
115 /* Set RF after the previous action is done. */
116 while (ppsc
->rfchange_inprogress
) {
120 *Wait too long, return false to avoid
123 if (rfwait_cnt
> 100)
127 ppsc
->rfchange_inprogress
= true;
128 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
134 rtstate
= ppsc
->rfpwr_state
;
136 switch (state_toset
) {
138 ppsc
->rfoff_reason
&= (~changesource
);
140 if ((changesource
== RF_CHANGE_BY_HW
) &&
141 (ppsc
->b_hwradiooff
== true)) {
142 ppsc
->b_hwradiooff
= false;
145 if (!ppsc
->rfoff_reason
) {
146 ppsc
->rfoff_reason
= 0;
147 b_actionallowed
= true;
154 if ((changesource
== RF_CHANGE_BY_HW
) &&
155 (ppsc
->b_hwradiooff
== false)) {
156 ppsc
->b_hwradiooff
= true;
159 ppsc
->rfoff_reason
|= changesource
;
160 b_actionallowed
= true;
164 ppsc
->rfoff_reason
|= changesource
;
165 b_actionallowed
= true;
169 RT_TRACE(COMP_ERR
, DBG_EMERG
, ("switch case not process \n"));
174 rtlpriv
->cfg
->ops
->set_rf_power_state(hw
, state_toset
);
176 if (!protect_or_not
) {
177 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
178 ppsc
->rfchange_inprogress
= false;
179 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
182 return b_actionallowed
;
184 //EXPORT_SYMBOL(rtl_ps_set_rf_state);
186 static void _rtl_ps_inactive_ps(struct ieee80211_hw
*hw
)
188 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
189 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
190 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
192 ppsc
->b_swrf_processing
= true;
194 if (ppsc
->inactive_pwrstate
== ERFON
&& rtlhal
->interface
== INTF_PCI
) {
195 if ((ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
) &&
196 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
) &&
197 rtlhal
->interface
== INTF_PCI
) {
198 rtlpriv
->intf_ops
->disable_aspm(hw
);
199 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
203 if (rtlpriv
->cfg
->ops
->get_btc_status()){
204 rtlpriv
->btcoexist
.btc_ops
->btc_ips_notify(rtlpriv
,
205 ppsc
->inactive_pwrstate
);
207 rtl_ps_set_rf_state(hw
, ppsc
->inactive_pwrstate
,
208 RF_CHANGE_BY_IPS
, false);
210 if (ppsc
->inactive_pwrstate
== ERFOFF
&&
211 rtlhal
->interface
== INTF_PCI
) {
212 if (ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
&&
213 !RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
214 rtlpriv
->intf_ops
->enable_aspm(hw
);
215 RT_SET_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
219 ppsc
->b_swrf_processing
= false;
222 void rtl_ips_nic_off_wq_callback(void *data
)
224 struct rtl_works
*rtlworks
=
225 container_of_dwork_rtl(data
, struct rtl_works
, ips_nic_off_wq
);
226 struct ieee80211_hw
*hw
= rtlworks
->hw
;
227 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
228 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
229 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
230 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
231 enum rf_pwrstate rtstate
;
233 if (mac
->opmode
!= NL80211_IFTYPE_STATION
) {
234 RT_TRACE(COMP_ERR
, DBG_WARNING
, ("not station return\n"));
241 if (mac
->link_state
> MAC80211_NOLINK
)
244 if (is_hal_stop(rtlhal
))
247 if (rtlpriv
->sec
.being_setkey
)
250 if(rtlpriv
->cfg
->ops
->bt_turn_off_bt_coexist_before_enter_lps
)
251 rtlpriv
->cfg
->ops
->bt_turn_off_bt_coexist_before_enter_lps(hw
);
253 if (ppsc
->b_inactiveps
) {
254 rtstate
= ppsc
->rfpwr_state
;
257 *Do not enter IPS in the following conditions:
258 *(1) RF is already OFF or Sleep
259 *(2) b_swrf_processing (indicates the IPS is still under going)
260 *(3) Connectted (only disconnected can trigger IPS)
261 *(4) IBSS (send Beacon)
262 *(5) AP mode (send Beacon)
263 *(6) monitor mode (rcv packet)
266 if (rtstate
== ERFON
&&
267 !ppsc
->b_swrf_processing
&&
268 (mac
->link_state
== MAC80211_NOLINK
) &&
269 !mac
->act_scanning
) {
270 RT_TRACE(COMP_RF
, DBG_LOUD
,
271 ("IPSEnter(): Turn off RF.\n"));
273 ppsc
->inactive_pwrstate
= ERFOFF
;
274 ppsc
->b_in_powersavemode
= true;
276 /*rtl_pci_reset_trx_ring(hw); */
277 _rtl_ps_inactive_ps(hw
);
282 void rtl_ips_nic_off(struct ieee80211_hw
*hw
)
284 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
287 *because when link with ap, mac80211 will ask us
288 *to disable nic quickly after scan before linking,
289 *this will cause link failed, so we delay 100ms here
291 queue_delayed_work(rtlpriv
->works
.rtl_wq
,
292 &rtlpriv
->works
.ips_nic_off_wq
, MSECS(100));
295 /* NOTICE: any opmode should exc nic_on, or disable without
296 * nic_on may something wrong, like adhoc TP*/
297 void rtl_ips_nic_on(struct ieee80211_hw
*hw
)
299 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
300 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
301 enum rf_pwrstate rtstate
;
303 cancel_delayed_work(&rtlpriv
->works
.ips_nic_off_wq
);
305 spin_lock(&rtlpriv
->locks
.ips_lock
);
306 if (ppsc
->b_inactiveps
) {
307 rtstate
= ppsc
->rfpwr_state
;
309 if (rtstate
!= ERFON
&&
310 !ppsc
->b_swrf_processing
&&
311 ppsc
->rfoff_reason
<= RF_CHANGE_BY_IPS
) {
313 ppsc
->inactive_pwrstate
= ERFON
;
314 ppsc
->b_in_powersavemode
= false;
315 _rtl_ps_inactive_ps(hw
);
318 spin_unlock(&rtlpriv
->locks
.ips_lock
);
324 *Determine if we can set Fw into PS mode
325 *in current condition.Return true if it
328 static bool rtl_get_fwlps_doze(struct ieee80211_hw
*hw
)
330 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
331 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
332 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
335 ps_timediff
= jiffies_to_msecs(jiffies
-
336 ppsc
->last_delaylps_stamp_jiffies
);
338 if (ps_timediff
< 2000) {
339 RT_TRACE(COMP_POWER
, DBG_LOUD
,
340 ("Delay enter Fw LPS for DHCP, ARP,"
341 " or EAPOL exchanging state.\n"));
345 if (mac
->link_state
!= MAC80211_LINKED
)
348 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
354 /* Change current and default preamble mode.*/
355 void rtl_lps_set_psmode(struct ieee80211_hw
*hw
, u8 rt_psmode
)
357 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
358 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
359 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
362 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
365 if (mac
->link_state
!= MAC80211_LINKED
)
368 if (ppsc
->dot11_psmode
== rt_psmode
)
371 /* Update power save mode configured. */
372 ppsc
->dot11_psmode
= rt_psmode
;
377 * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
378 * cmd to set Fw into PS mode.
380 * Send H2C fw_pwrmode cmd to Fw to set Fw into Active
381 * mode and set RPWM to turn RF on.
384 if ((ppsc
->b_fwctrl_lps
) && ppsc
->report_linked
) {
385 if (ppsc
->dot11_psmode
== EACTIVE
) {
386 RT_TRACE(COMP_RF
, DBG_DMESG
,
387 ("FW LPS leave ps_mode:%x\n",
390 ppsc
->pwr_mode
= FW_PS_ACTIVE_MODE
;
392 rtlpriv
->cfg
->ops
->set_hw_reg(hw
, HW_VAR_FW_LPS_ACTION
,
393 (u8
*)(&enter_fwlps
));
394 if (ppsc
->p2p_ps_info
.opp_ps
)
395 rtl_p2p_ps_cmd(hw
,P2P_PS_ENABLE
);
398 if (rtl_get_fwlps_doze(hw
)) {
399 RT_TRACE(COMP_RF
, DBG_DMESG
,
400 ("FW LPS enter ps_mode:%x\n",
401 ppsc
->fwctrl_psmode
));
403 ppsc
->pwr_mode
= ppsc
->fwctrl_psmode
;
405 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
406 HW_VAR_FW_LPS_ACTION
,
407 (u8
*)(&enter_fwlps
));
410 /* Reset the power save related parameters. */
411 ppsc
->dot11_psmode
= EACTIVE
;
417 /*Enter the leisure power save mode.*/
418 void rtl_lps_enter(struct ieee80211_hw
*hw
)
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
);
425 if (!ppsc
->b_fwctrl_lps
)
428 if (rtlpriv
->sec
.being_setkey
)
431 if (rtlpriv
->link_info
.b_busytraffic
)
434 /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
435 if (mac
->cnt_after_linked
< 5)
438 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
441 if (mac
->link_state
!= MAC80211_LINKED
)
444 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
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(COMP_POWER
, DBG_LOUD
,
450 ("Enter 802.11 power save mode...\n"));
452 rtl_lps_set_psmode(hw
, EAUTOPS
);
456 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
459 /*Leave the leisure power save mode.*/
460 void rtl_lps_leave(struct ieee80211_hw
*hw
)
462 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
463 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
464 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
467 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
469 if (ppsc
->b_fwctrl_lps
) {
470 if (ppsc
->dot11_psmode
!= EACTIVE
) {
473 rtlpriv
->cfg
->ops
->enable_interrupt(hw
);
475 if (ppsc
->reg_rfps_level
& RT_RF_LPS_LEVEL_ASPM
&&
476 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
) &&
477 rtlhal
->interface
== INTF_PCI
) {
478 rtlpriv
->intf_ops
->disable_aspm(hw
);
479 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
482 RT_TRACE(COMP_POWER
, DBG_LOUD
,
483 ("Busy Traffic,Leave 802.11 power save..\n"));
485 rtl_lps_set_psmode(hw
, EACTIVE
);
488 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
492 void rtl_swlps_beacon(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
494 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
495 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
496 struct ieee80211_hdr
*hdr
= (void *) data
;
497 struct ieee80211_tim_ie
*tim_ie
;
503 if (mac
->opmode
!= NL80211_IFTYPE_STATION
)
506 if (!rtlpriv
->psc
.b_swctrl_lps
)
509 if (rtlpriv
->mac80211
.link_state
!= MAC80211_LINKED
)
512 if (!rtlpriv
->psc
.sw_ps_enabled
)
515 if (rtlpriv
->psc
.b_fwctrl_lps
)
518 if (likely(!(hw
->conf
.flags
& IEEE80211_CONF_PS
)))
521 /* check if this really is a beacon */
522 if (!ieee80211_is_beacon(hdr
->frame_control
))
525 /* min. beacon length + FCS_LEN */
526 if (len
<= 40 + FCS_LEN
)
529 /* and only beacons from the associated BSSID, please */
530 if (ether_addr_equal(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
533 rtlpriv
->psc
.last_beacon
= jiffies
;
535 tim
= rtl_find_ie(data
, len
- FCS_LEN
, WLAN_EID_TIM
);
539 if (tim
[1] < sizeof(*tim_ie
))
543 tim_ie
= (struct ieee80211_tim_ie
*) &tim
[2];
545 /*<delete in kernel start>*/
546 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
547 /*<delete in kernel end>*/
548 if (!WARN_ON_ONCE(!hw
->conf
.ps_dtim_period
))
549 rtlpriv
->psc
.dtim_counter
= tim_ie
->dtim_count
;
550 /*<delete in kernel start>*/
552 if (!WARN_ON_ONCE(!mac
->vif
->bss_conf
.dtim_period
))
553 rtlpriv
->psc
.dtim_counter
= tim_ie
->dtim_count
;
555 /*<delete in kernel end>*/
557 /* Check whenever the PHY can be turned off again. */
559 /* 1. What about buffered unicast traffic for our AID? */
560 u_buffed
= ieee80211_check_tim(tim_ie
, tim_len
,
561 rtlpriv
->mac80211
.assoc_id
);
563 /* 2. Maybe the AP wants to send multicast/broadcast data? */
564 m_buffed
= tim_ie
->bitmap_ctrl
& 0x01;
565 rtlpriv
->psc
.multi_buffered
= m_buffed
;
567 /* unicast will process by mac80211 through
568 * set ~IEEE80211_CONF_PS, So we just check
569 * multicast frames here */
570 if (!m_buffed
) {//&&) {// !rtlpriv->psc.tx_doing) {
571 /* back to low-power land. and delay is
572 * prevent null power save frame tx fail */
573 queue_delayed_work(rtlpriv
->works
.rtl_wq
,
574 &rtlpriv
->works
.ps_work
, MSECS(5));
576 RT_TRACE(COMP_POWER
, DBG_DMESG
,
577 ("u_bufferd: %x, m_buffered: %x\n",
578 u_buffed
, m_buffed
));
582 void rtl_swlps_rf_awake(struct ieee80211_hw
*hw
)
584 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
585 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
586 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
589 if (!rtlpriv
->psc
.b_swctrl_lps
)
591 if (mac
->link_state
!= MAC80211_LINKED
)
594 if (ppsc
->reg_rfps_level
& RT_RF_LPS_LEVEL_ASPM
&&
595 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
596 rtlpriv
->intf_ops
->disable_aspm(hw
);
597 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
600 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
601 rtl_ps_set_rf_state(hw
, ERFON
, RF_CHANGE_BY_PS
, false);
602 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
605 void rtl_swlps_rfon_wq_callback(void *data
)
607 struct rtl_works
*rtlworks
=
608 container_of_dwork_rtl(data
, struct rtl_works
, ps_rfon_wq
);
609 struct ieee80211_hw
*hw
= rtlworks
->hw
;
611 rtl_swlps_rf_awake(hw
);
614 void rtl_swlps_rf_sleep(struct ieee80211_hw
*hw
)
616 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
617 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
618 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
622 if (!rtlpriv
->psc
.sw_ps_enabled
)
625 if ((rtlpriv
->sec
.being_setkey
) ||
626 (mac
->opmode
== NL80211_IFTYPE_ADHOC
))
629 /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
630 if ((mac
->link_state
!= MAC80211_LINKED
) || (mac
->cnt_after_linked
< 5))
633 if (rtlpriv
->link_info
.b_busytraffic
)
636 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
637 if (rtlpriv
->psc
.rfchange_inprogress
) {
638 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
641 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
643 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
644 rtl_ps_set_rf_state(hw
, ERFSLEEP
, RF_CHANGE_BY_PS
,false);
645 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
647 if (ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
&&
648 !RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
649 rtlpriv
->intf_ops
->enable_aspm(hw
);
650 RT_SET_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
653 /* here is power save alg, when this beacon is DTIM
654 * we will set sleep time to dtim_period * n;
655 * when this beacon is not DTIM, we will set sleep
656 * time to sleep_intv = rtlpriv->psc.dtim_counter or
657 * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
659 /*<delete in kernel start>*/
660 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
661 /*<delete in kernel end>*/
662 if (rtlpriv
->psc
.dtim_counter
== 0) {
663 if (hw
->conf
.ps_dtim_period
== 1)
664 sleep_intv
= hw
->conf
.ps_dtim_period
* 2;
666 sleep_intv
= hw
->conf
.ps_dtim_period
;
668 sleep_intv
= rtlpriv
->psc
.dtim_counter
;
670 /*<delete in kernel start>*/
672 if (rtlpriv
->psc
.dtim_counter
== 0) {
673 if (mac
->vif
->bss_conf
.dtim_period
== 1)
674 sleep_intv
= mac
->vif
->bss_conf
.dtim_period
* 2;
676 sleep_intv
= mac
->vif
->bss_conf
.dtim_period
;
678 sleep_intv
= rtlpriv
->psc
.dtim_counter
;
681 /*<delete in kernel end>*/
683 if (sleep_intv
> MAX_SW_LPS_SLEEP_INTV
)
684 sleep_intv
= MAX_SW_LPS_SLEEP_INTV
;
686 /* this print should always be dtim_conter = 0 &
687 * sleep = dtim_period, that meaons, we should
688 * awake before every dtim */
689 RT_TRACE(COMP_POWER
, DBG_DMESG
,
690 ("dtim_counter:%x will sleep :%d beacon_intv\n",
691 rtlpriv
->psc
.dtim_counter
, sleep_intv
));
693 /* we tested that 40ms is enough for sw & hw sw delay */
694 queue_delayed_work(rtlpriv
->works
.rtl_wq
, &rtlpriv
->works
.ps_rfon_wq
,
695 MSECS(sleep_intv
* mac
->vif
->bss_conf
.beacon_int
- 40));
699 void rtl_swlps_wq_callback(void *data
)
701 struct rtl_works
*rtlworks
=
702 container_of_dwork_rtl(data
, struct rtl_works
, ps_work
);
703 struct ieee80211_hw
*hw
= rtlworks
->hw
;
704 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
707 ps
= (hw
->conf
.flags
& IEEE80211_CONF_PS
);
709 /* we can sleep after ps null send ok */
710 if (rtlpriv
->psc
.state_inap
) {
711 rtl_swlps_rf_sleep(hw
);
713 if (rtlpriv
->psc
.state
&& !ps
) {
714 rtlpriv
->psc
.sleep_ms
=
715 jiffies_to_msecs(jiffies
-
716 rtlpriv
->psc
.last_action
);
720 rtlpriv
->psc
.last_slept
= jiffies
;
722 rtlpriv
->psc
.last_action
= jiffies
;
723 rtlpriv
->psc
.state
= ps
;
728 void rtl_p2p_noa_ie(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
730 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
731 struct ieee80211_mgmt
*mgmt
= (void *)data
;
732 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
735 static u8 p2p_oui_ie_type
[4] = {0x50, 0x6f, 0x9a, 0x09};
736 u8 noa_num
, index
,i
, noa_index
= 0;
737 bool find_p2p_ie
= false , find_p2p_ps_ie
= false;
738 pos
= (u8
*)mgmt
->u
.beacon
.variable
;
742 while (pos
+ 1 < end
) {
744 if (pos
+ 2 + pos
[1] > end
)
747 if (pos
[0] == 221 && pos
[1] > 4) {
748 if (memcmp(&pos
[2], p2p_oui_ie_type
, 4) == 0) {
760 while (ie
+ 1 < end
) {
761 noa_len
= READEF2BYTE(&ie
[1]);
762 if (ie
+ 3 + ie
[1] > end
)
766 find_p2p_ps_ie
= true;
767 if ( (noa_len
- 2) % 13 != 0){
768 RT_TRACE(COMP_INIT
, DBG_LOUD
,
769 ("P2P notice of absence: "
770 "invalid length.%d\n",noa_len
));
773 noa_num
= (noa_len
- 2) / 13;
776 if (rtlpriv
->psc
.p2p_ps_info
.p2p_ps_mode
== P2P_PS_NONE
777 || noa_index
!= p2pinfo
->noa_index
) {
778 RT_TRACE(COMP_FW
, DBG_LOUD
,
779 ("update NOA ie.\n"));
780 p2pinfo
->noa_index
= noa_index
;
781 p2pinfo
->opp_ps
= (ie
[4] >> 7);
782 p2pinfo
->ctwindow
= ie
[4] & 0x7F;
783 p2pinfo
->noa_num
= noa_num
;
785 for (i
= 0; i
< noa_num
; i
++){
786 p2pinfo
->noa_count_type
[i
] =
787 READEF1BYTE(ie
+index
);
789 p2pinfo
->noa_duration
[i
] =
790 READEF4BYTE(ie
+index
);
792 p2pinfo
->noa_interval
[i
] =
793 READEF4BYTE(ie
+index
);
795 p2pinfo
->noa_start_time
[i
] =
796 READEF4BYTE(ie
+index
);
800 if (p2pinfo
->opp_ps
== 1) {
801 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
802 /* Driver should wait LPS
803 * entering CTWindow*/
804 if (rtlpriv
->psc
.b_fw_current_inpsmode
){
808 } else if (p2pinfo
->noa_num
> 0) {
809 p2pinfo
->p2p_ps_mode
= P2P_PS_NOA
;
810 rtl_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
811 } else if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
812 rtl_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
821 if (find_p2p_ie
== true) {
822 if ((p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) &&
823 (find_p2p_ps_ie
== false))
824 rtl_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
828 void rtl_p2p_action_ie(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
830 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
831 struct ieee80211_mgmt
*mgmt
= (void *)data
;
832 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
833 bool find_p2p_ie
= false , find_p2p_ps_ie
= false;
834 u8 noa_num
, index
,i
, noa_index
= 0;
837 static u8 p2p_oui_ie_type
[4] = {0x50, 0x6f, 0x9a, 0x09};
839 pos
= (u8
*) &mgmt
->u
.action
.category
;
843 if (pos
[0] == 0x7f ) {
844 if (memcmp(&pos
[1], p2p_oui_ie_type
, 4) == 0) {
853 RT_TRACE(COMP_FW
, DBG_LOUD
, ("action frame find P2P IE.\n"));
855 while (ie
+ 1 < end
) {
856 noa_len
= READEF2BYTE(&ie
[1]);
857 if (ie
+ 3 + ie
[1] > end
)
861 RT_TRACE(COMP_FW
, DBG_LOUD
, ("find NOA IE.\n"));
862 RT_PRINT_DATA(rtlpriv
, COMP_FW
, DBG_LOUD
, ("noa ie "),
864 find_p2p_ps_ie
= true;
865 if ( (noa_len
- 2) % 13 != 0){
866 RT_TRACE(COMP_FW
, DBG_LOUD
,
867 ("P2P notice of absence: "
868 "invalid length.%d\n",noa_len
));
871 noa_num
= (noa_len
- 2) / 13;
874 if (rtlpriv
->psc
.p2p_ps_info
.p2p_ps_mode
== P2P_PS_NONE
875 || noa_index
!= p2pinfo
->noa_index
) {
876 p2pinfo
->noa_index
= noa_index
;
877 p2pinfo
->opp_ps
= (ie
[4] >> 7);
878 p2pinfo
->ctwindow
= ie
[4] & 0x7F;
879 p2pinfo
->noa_num
= noa_num
;
881 for (i
= 0; i
< noa_num
; i
++){
882 p2pinfo
->noa_count_type
[i
] =
883 READEF1BYTE(ie
+index
);
885 p2pinfo
->noa_duration
[i
] =
886 READEF4BYTE(ie
+index
);
888 p2pinfo
->noa_interval
[i
] =
889 READEF4BYTE(ie
+index
);
891 p2pinfo
->noa_start_time
[i
] =
892 READEF4BYTE(ie
+index
);
896 if (p2pinfo
->opp_ps
== 1) {
897 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
898 /* Driver should wait LPS
899 * entering CTWindow */
900 if (rtlpriv
->psc
.b_fw_current_inpsmode
){
904 } else if (p2pinfo
->noa_num
> 0) {
905 p2pinfo
->p2p_ps_mode
= P2P_PS_NOA
;
906 rtl_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
907 } else if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
908 rtl_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
921 void rtl_p2p_ps_cmd(struct ieee80211_hw
*hw
,u8 p2p_ps_state
)
923 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
924 struct rtl_ps_ctl
*rtlps
= rtl_psc(rtl_priv(hw
));
925 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
927 RT_TRACE(COMP_FW
, DBG_LOUD
, (" p2p state %x\n",p2p_ps_state
));
928 switch (p2p_ps_state
) {
930 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
931 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
932 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
933 (u8
*)(&p2p_ps_state
));
935 p2pinfo
->noa_index
= 0;
936 p2pinfo
->ctwindow
= 0;
938 p2pinfo
->noa_num
= 0;
939 p2pinfo
->p2p_ps_mode
= P2P_PS_NONE
;
940 if (rtlps
->b_fw_current_inpsmode
== true) {
941 if (rtlps
->smart_ps
== 0) {
943 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
944 HW_VAR_H2C_FW_PWRMODE
,
945 (u8
*)(&rtlps
->pwr_mode
));
951 if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
952 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
954 if (p2pinfo
->ctwindow
> 0) {
955 if (rtlps
->smart_ps
!= 0){
957 rtlpriv
->cfg
->ops
->set_hw_reg(
958 hw
, HW_VAR_H2C_FW_PWRMODE
,
959 (u8
*)(&rtlps
->pwr_mode
));
962 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
963 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
964 (u8
*)(&p2p_ps_state
));
969 case P2P_PS_SCAN_DONE
:
970 case P2P_PS_ALLSTASLEEP
:
971 if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
972 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
973 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
974 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
975 (u8
*)(&p2p_ps_state
));
982 RT_TRACE(COMP_FW
, DBG_LOUD
, (" ctwindow %x oppps %x \n",
983 p2pinfo
->ctwindow
,p2pinfo
->opp_ps
));
984 RT_TRACE(COMP_FW
, DBG_LOUD
, ("count %x duration %x index %x interval %x"
985 " start time %x noa num %x\n",
986 p2pinfo
->noa_count_type
[0],
987 p2pinfo
->noa_duration
[0],
989 p2pinfo
->noa_interval
[0],
990 p2pinfo
->noa_start_time
[0],
992 RT_TRACE(COMP_FW
, DBG_LOUD
, ("end\n"));
995 void rtl_p2p_info(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
997 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
998 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
999 struct ieee80211_hdr
*hdr
= (void *) data
;
1003 if (mac
->link_state
!= MAC80211_LINKED
)
1005 /* min. beacon length + FCS_LEN */
1006 if (len
<= 40 + FCS_LEN
)
1009 /* and only beacons from the associated BSSID, please */
1010 if (ether_addr_equal(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
1013 /* check if this really is a beacon */
1014 if (!(ieee80211_is_beacon(hdr
->frame_control
) ||
1015 ieee80211_is_probe_resp(hdr
->frame_control
) ||
1016 ieee80211_is_action(hdr
->frame_control
)))
1019 if (ieee80211_is_action(hdr
->frame_control
)) {
1020 rtl_p2p_action_ie(hw
,data
,len
- FCS_LEN
);
1022 rtl_p2p_noa_ie(hw
,data
,len
- FCS_LEN
);