1 /******************************************************************************
3 * Copyright(c) 2009-2012 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 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
29 #include <linux/export.h>
30 #include "btcoexist/rtl_btc.h"
32 bool rtl_ps_enable_nic(struct ieee80211_hw
*hw
)
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
));
38 /*<1> reset trx ring */
39 if (rtlhal
->interface
== INTF_PCI
)
40 rtlpriv
->intf_ops
->reset_trx_ring(hw
);
42 if (is_hal_stop(rtlhal
))
43 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
44 "Driver is already down!\n");
46 /*<2> Enable Adapter */
47 if (rtlpriv
->cfg
->ops
->hw_init(hw
))
49 RT_CLEAR_PS_LEVEL(ppsc
, RT_RF_OFF_LEVL_HALT_NIC
);
51 /*<3> Enable Interrupt */
52 rtlpriv
->cfg
->ops
->enable_interrupt(hw
);
55 rtl_watch_dog_timer_callback((unsigned long)hw
);
59 EXPORT_SYMBOL(rtl_ps_enable_nic
);
61 bool rtl_ps_disable_nic(struct ieee80211_hw
*hw
)
63 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
65 /*<1> Stop all timer */
66 rtl_deinit_deferred_work(hw
);
68 /*<2> Disable Interrupt */
69 rtlpriv
->cfg
->ops
->disable_interrupt(hw
);
70 tasklet_kill(&rtlpriv
->works
.irq_tasklet
);
72 /*<3> Disable Adapter */
73 rtlpriv
->cfg
->ops
->hw_disable(hw
);
77 EXPORT_SYMBOL(rtl_ps_disable_nic
);
79 bool rtl_ps_set_rf_state(struct ieee80211_hw
*hw
,
80 enum rf_pwrstate state_toset
,
81 u32 changesource
, bool protect_or_not
)
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;
92 /*Only one thread can change
93 *the RF state at one time, and others
94 *should wait to be executed.
97 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
98 if (ppsc
->rfchange_inprogress
) {
99 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
101 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
102 "RF Change in progress! Wait to set..state_toset(%d).\n",
105 /* Set RF after the previous action is done. */
106 while (ppsc
->rfchange_inprogress
) {
109 /*Wait too long, return false to avoid
112 if (rfwait_cnt
> 100)
116 ppsc
->rfchange_inprogress
= true;
117 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
123 rtstate
= ppsc
->rfpwr_state
;
125 switch (state_toset
) {
127 ppsc
->rfoff_reason
&= (~changesource
);
129 if ((changesource
== RF_CHANGE_BY_HW
) &&
130 (ppsc
->hwradiooff
)) {
131 ppsc
->hwradiooff
= false;
134 if (!ppsc
->rfoff_reason
) {
135 ppsc
->rfoff_reason
= 0;
136 actionallowed
= true;
143 if ((changesource
== RF_CHANGE_BY_HW
) && !ppsc
->hwradiooff
) {
144 ppsc
->hwradiooff
= true;
147 ppsc
->rfoff_reason
|= changesource
;
148 actionallowed
= true;
152 ppsc
->rfoff_reason
|= changesource
;
153 actionallowed
= true;
157 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
158 "switch case not processed\n");
163 rtlpriv
->cfg
->ops
->set_rf_power_state(hw
, state_toset
);
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
);
171 return actionallowed
;
173 EXPORT_SYMBOL(rtl_ps_set_rf_state
);
175 static void _rtl_ps_inactive_ps(struct ieee80211_hw
*hw
)
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
));
181 ppsc
->swrf_processing
= true;
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
);
193 rtl_ps_set_rf_state(hw
, ppsc
->inactive_pwrstate
,
194 RF_CHANGE_BY_IPS
, false);
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
);
205 ppsc
->swrf_processing
= false;
208 void rtl_ips_nic_off_wq_callback(void *data
)
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
;
219 if (mac
->opmode
!= NL80211_IFTYPE_STATION
) {
220 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
221 "not station return\n");
228 if (mac
->link_state
> MAC80211_NOLINK
)
231 if (is_hal_stop(rtlhal
))
234 if (rtlpriv
->sec
.being_setkey
)
237 if (rtlpriv
->cfg
->ops
->bt_coex_off_before_lps
)
238 rtlpriv
->cfg
->ops
->bt_coex_off_before_lps(hw
);
240 if (ppsc
->inactiveps
) {
241 rtstate
= ppsc
->rfpwr_state
;
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)
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");
260 ppsc
->inactive_pwrstate
= ERFOFF
;
261 ppsc
->in_powersavemode
= true;
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
);
268 /*rtl_pci_reset_trx_ring(hw); */
269 _rtl_ps_inactive_ps(hw
);
274 void rtl_ips_nic_off(struct ieee80211_hw
*hw
)
276 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
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
282 queue_delayed_work(rtlpriv
->works
.rtl_wq
,
283 &rtlpriv
->works
.ips_nic_off_wq
, MSECS(100));
286 /* NOTICE: any opmode should exc nic_on, or disable without
287 * nic_on may something wrong, like adhoc TP
289 void rtl_ips_nic_on(struct ieee80211_hw
*hw
)
291 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
292 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
293 enum rf_pwrstate rtstate
;
295 cancel_delayed_work(&rtlpriv
->works
.ips_nic_off_wq
);
297 spin_lock(&rtlpriv
->locks
.ips_lock
);
298 if (ppsc
->inactiveps
) {
299 rtstate
= ppsc
->rfpwr_state
;
301 if (rtstate
!= ERFON
&&
302 !ppsc
->swrf_processing
&&
303 ppsc
->rfoff_reason
<= RF_CHANGE_BY_IPS
) {
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
);
314 spin_unlock(&rtlpriv
->locks
.ips_lock
);
316 EXPORT_SYMBOL_GPL(rtl_ips_nic_on
);
321 *Determine if we can set Fw into PS mode
322 *in current condition.Return TRUE if it
325 static bool rtl_get_fwlps_doze(struct ieee80211_hw
*hw
)
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
));
332 ps_timediff
= jiffies_to_msecs(jiffies
-
333 ppsc
->last_delaylps_stamp_jiffies
);
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");
341 if (mac
->link_state
!= MAC80211_LINKED
)
344 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
350 /* Change current and default preamble mode.*/
351 void rtl_lps_set_psmode(struct ieee80211_hw
*hw
, u8 rt_psmode
)
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
));
358 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
361 if (mac
->link_state
!= MAC80211_LINKED
)
364 if (ppsc
->dot11_psmode
== rt_psmode
)
367 /* Update power save mode configured. */
368 ppsc
->dot11_psmode
= rt_psmode
;
373 * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
374 * cmd to set Fw into PS mode.
376 * Send H2C fw_pwrmode cmd to Fw to set Fw into Active
377 * mode and set RPWM to turn RF on.
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",
386 ppsc
->pwr_mode
= FW_PS_ACTIVE_MODE
;
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
);
393 if (rtlpriv
->cfg
->ops
->get_btc_status())
394 rtlpriv
->btcoexist
.btc_ops
->btc_lps_notify(rtlpriv
, rt_psmode
);
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
);
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
->fwctrl_lps
)
428 if (rtlpriv
->sec
.being_setkey
)
431 if (rtlpriv
->link_info
.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(rtlpriv
, 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
);
458 EXPORT_SYMBOL(rtl_lps_enter
);
460 /*Leave the leisure power save mode.*/
461 void rtl_lps_leave(struct ieee80211_hw
*hw
)
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
));
468 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
470 if (ppsc
->fwctrl_lps
) {
471 if (ppsc
->dot11_psmode
!= EACTIVE
) {
474 /*rtlpriv->cfg->ops->enable_interrupt(hw); */
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
);
483 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
,
484 "Busy Traffic,Leave 802.11 power save..\n");
486 rtl_lps_set_psmode(hw
, EACTIVE
);
489 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
491 EXPORT_SYMBOL(rtl_lps_leave
);
494 void rtl_swlps_beacon(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
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
;
505 if (mac
->opmode
!= NL80211_IFTYPE_STATION
)
508 if (!rtlpriv
->psc
.swctrl_lps
)
511 if (rtlpriv
->mac80211
.link_state
!= MAC80211_LINKED
)
514 if (!rtlpriv
->psc
.sw_ps_enabled
)
517 if (rtlpriv
->psc
.fwctrl_lps
)
520 if (likely(!(hw
->conf
.flags
& IEEE80211_CONF_PS
)))
523 /* check if this really is a beacon */
524 if (!ieee80211_is_beacon(hdr
->frame_control
))
527 /* min. beacon length + FCS_LEN */
528 if (len
<= 40 + FCS_LEN
)
531 /* and only beacons from the associated BSSID, please */
532 if (!ether_addr_equal_64bits(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
535 rtlpriv
->psc
.last_beacon
= jiffies
;
537 tim
= rtl_find_ie(data
, len
- FCS_LEN
, WLAN_EID_TIM
);
541 if (tim
[1] < sizeof(*tim_ie
))
545 tim_ie
= (struct ieee80211_tim_ie
*) &tim
[2];
547 if (!WARN_ON_ONCE(!hw
->conf
.ps_dtim_period
))
548 rtlpriv
->psc
.dtim_counter
= tim_ie
->dtim_count
;
550 /* Check whenever the PHY can be turned off again. */
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
);
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
;
560 /* unicast will process by mac80211 through
561 * set ~IEEE80211_CONF_PS, So we just check
562 * multicast frames here */
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));
569 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_DMESG
,
570 "u_bufferd: %x, m_buffered: %x\n", u_buffed
, m_buffed
);
573 EXPORT_SYMBOL_GPL(rtl_swlps_beacon
);
575 void rtl_swlps_rf_awake(struct ieee80211_hw
*hw
)
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
));
582 if (!rtlpriv
->psc
.swctrl_lps
)
584 if (mac
->link_state
!= MAC80211_LINKED
)
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
);
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
);
598 void rtl_swlps_rfon_wq_callback(void *data
)
600 struct rtl_works
*rtlworks
=
601 container_of_dwork_rtl(data
, struct rtl_works
, ps_rfon_wq
);
602 struct ieee80211_hw
*hw
= rtlworks
->hw
;
604 rtl_swlps_rf_awake(hw
);
607 void rtl_swlps_rf_sleep(struct ieee80211_hw
*hw
)
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
));
615 if (!rtlpriv
->psc
.sw_ps_enabled
)
618 if ((rtlpriv
->sec
.being_setkey
) ||
619 (mac
->opmode
== NL80211_IFTYPE_ADHOC
))
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))
626 if (rtlpriv
->link_info
.busytraffic
)
629 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
630 if (rtlpriv
->psc
.rfchange_inprogress
) {
631 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
634 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
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
);
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
);
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) */
652 if (rtlpriv
->psc
.dtim_counter
== 0) {
653 if (hw
->conf
.ps_dtim_period
== 1)
654 sleep_intv
= hw
->conf
.ps_dtim_period
* 2;
656 sleep_intv
= hw
->conf
.ps_dtim_period
;
658 sleep_intv
= rtlpriv
->psc
.dtim_counter
;
661 if (sleep_intv
> MAX_SW_LPS_SLEEP_INTV
)
662 sleep_intv
= MAX_SW_LPS_SLEEP_INTV
;
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
);
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));
676 void rtl_lps_change_work_callback(struct work_struct
*work
)
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
);
683 if (rtlpriv
->enter_ps
)
688 EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback
);
690 void rtl_swlps_wq_callback(void *data
)
692 struct rtl_works
*rtlworks
= container_of_dwork_rtl(data
,
695 struct ieee80211_hw
*hw
= rtlworks
->hw
;
696 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
699 ps
= (hw
->conf
.flags
& IEEE80211_CONF_PS
);
701 /* we can sleep after ps null send ok */
702 if (rtlpriv
->psc
.state_inap
) {
703 rtl_swlps_rf_sleep(hw
);
705 if (rtlpriv
->psc
.state
&& !ps
) {
706 rtlpriv
->psc
.sleep_ms
= jiffies_to_msecs(jiffies
-
707 rtlpriv
->psc
.last_action
);
711 rtlpriv
->psc
.last_slept
= jiffies
;
713 rtlpriv
->psc
.last_action
= jiffies
;
714 rtlpriv
->psc
.state
= ps
;
718 static void rtl_p2p_noa_ie(struct ieee80211_hw
*hw
, void *data
,
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
);
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
;
733 while (pos
+ 1 < end
) {
734 if (pos
+ 2 + pos
[1] > end
)
737 if (pos
[0] == 221 && pos
[1] > 4) {
738 if (memcmp(&pos
[2], p2p_oui_ie_type
, 4) == 0) {
750 while (ie
+ 1 < end
) {
751 noa_len
= READEF2BYTE((__le16
*)&ie
[1]);
752 if (ie
+ 3 + ie
[1] > end
)
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",
763 noa_num
= (noa_len
- 2) / 13;
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
,
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
;
775 for (i
= 0; i
< noa_num
; i
++) {
776 p2pinfo
->noa_count_type
[i
] =
777 READEF1BYTE(ie
+index
);
779 p2pinfo
->noa_duration
[i
] =
780 READEF4BYTE((__le32
*)ie
+index
);
782 p2pinfo
->noa_interval
[i
] =
783 READEF4BYTE((__le32
*)ie
+index
);
785 p2pinfo
->noa_start_time
[i
] =
786 READEF4BYTE((__le32
*)ie
+index
);
790 if (p2pinfo
->opp_ps
== 1) {
791 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
792 /* Driver should wait LPS entering
795 if (rtlpriv
->psc
.fw_current_inpsmode
)
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
);
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
);
817 static void rtl_p2p_action_ie(struct ieee80211_hw
*hw
, void *data
,
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;
826 static u8 p2p_oui_ie_type
[4] = {0x50, 0x6f, 0x9a, 0x09};
828 pos
= (u8
*)&mgmt
->u
.action
.category
;
832 if (pos
[0] == 0x7f) {
833 if (memcmp(&pos
[1], p2p_oui_ie_type
, 4) == 0)
840 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "action frame find P2P IE.\n");
842 while (ie
+ 1 < end
) {
843 noa_len
= READEF2BYTE((__le16
*)&ie
[1]);
844 if (ie
+ 3 + ie
[1] > end
)
848 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "find NOA IE.\n");
849 RT_PRINT_DATA(rtlpriv
, COMP_FW
, DBG_LOUD
, "noa ie ",
851 if ((noa_len
- 2) % 13 != 0) {
852 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
853 "P2P notice of absence: invalid length.%d\n",
857 noa_num
= (noa_len
- 2) / 13;
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
;
867 for (i
= 0; i
< noa_num
; i
++) {
868 p2pinfo
->noa_count_type
[i
] =
869 READEF1BYTE(ie
+index
);
871 p2pinfo
->noa_duration
[i
] =
872 READEF4BYTE((__le32
*)ie
+index
);
874 p2pinfo
->noa_interval
[i
] =
875 READEF4BYTE((__le32
*)ie
+index
);
877 p2pinfo
->noa_start_time
[i
] =
878 READEF4BYTE((__le32
*)ie
+index
);
882 if (p2pinfo
->opp_ps
== 1) {
883 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
884 /* Driver should wait LPS entering
887 if (rtlpriv
->psc
.fw_current_inpsmode
)
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
);
903 void rtl_p2p_ps_cmd(struct ieee80211_hw
*hw
, u8 p2p_ps_state
)
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
);
909 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, " p2p state %x\n" , p2p_ps_state
);
910 switch (p2p_ps_state
) {
912 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
913 rtlpriv
->cfg
->ops
->set_hw_reg(hw
, HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
915 p2pinfo
->noa_index
= 0;
916 p2pinfo
->ctwindow
= 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) {
923 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
924 HW_VAR_H2C_FW_PWRMODE
,
931 if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
932 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
934 if (p2pinfo
->ctwindow
> 0) {
935 if (rtlps
->smart_ps
!= 0) {
937 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
938 HW_VAR_H2C_FW_PWRMODE
,
942 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
943 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
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
,
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],
969 p2pinfo
->noa_interval
[0],
970 p2pinfo
->noa_start_time
[0],
972 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "end\n");
975 void rtl_p2p_info(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
977 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
978 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
979 struct ieee80211_hdr
*hdr
= data
;
983 if (mac
->link_state
!= MAC80211_LINKED
)
985 /* min. beacon length + FCS_LEN */
986 if (len
<= 40 + FCS_LEN
)
989 /* and only beacons from the associated BSSID, please */
990 if (!ether_addr_equal_64bits(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
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
)))
999 if (ieee80211_is_action(hdr
->frame_control
))
1000 rtl_p2p_action_ie(hw
, data
, len
- FCS_LEN
);
1002 rtl_p2p_noa_ie(hw
, data
, len
- FCS_LEN
);
1004 EXPORT_SYMBOL_GPL(rtl_p2p_info
);