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 * 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 "btcoexist/rtl_btc.h"
31 bool stg_rtl_ps_enable_nic(struct ieee80211_hw
*hw
)
33 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
34 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
35 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
36 bool init_status
= true;
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(COMP_ERR
, DBG_WARNING
, ("Driver is already down!\n"));
45 /*<2> Enable Adapter */
46 rtlpriv
->cfg
->ops
->hw_init(hw
);
47 RT_CLEAR_PS_LEVEL(ppsc
, RT_RF_OFF_LEVL_HALT_NIC
);
48 /*init_status = false; */
50 /*<3> Enable Interrupt */
51 rtlpriv
->cfg
->ops
->enable_interrupt(hw
);
54 rtl92e_watch_dog_timer_callback((unsigned long)hw
);
58 EXPORT_SYMBOL(stg_rtl_ps_enable_nic
);
60 bool stg_rtl_ps_disable_nic(struct ieee80211_hw
*hw
)
63 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
65 /*<1> Stop all timer */
66 rtl92e_deinit_deferred_work(hw
);
68 /*<2> Disable Interrupt */
69 rtlpriv
->cfg
->ops
->disable_interrupt(hw
);
71 /*<3> Disable Adapter */
72 rtlpriv
->cfg
->ops
->hw_disable(hw
);
76 EXPORT_SYMBOL(stg_rtl_ps_disable_nic
);
78 bool stg_rtl_ps_set_rf_state(struct ieee80211_hw
*hw
,
79 enum rf_pwrstate state_toset
,
80 u32 changesource
, bool protect_or_not
)
82 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
83 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
84 enum rf_pwrstate rtstate
;
85 bool b_actionallowed
= false;
88 /*protect_or_not = true; */
94 *Only one thread can change
95 *the RF state at one time, and others
96 *should wait to be executed.
99 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
100 if (ppsc
->rfchange_inprogress
) {
101 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
103 RT_TRACE(COMP_ERR
, DBG_WARNING
,
104 ("RF Change in progress! Wait to set..state_toset(%d)\n",
107 /* Set RF after the previous action is done. */
108 while (ppsc
->rfchange_inprogress
) {
112 *Wait too long, return false to avoid
115 if (rfwait_cnt
> 100)
119 ppsc
->rfchange_inprogress
= true;
120 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
126 rtstate
= ppsc
->rfpwr_state
;
128 switch (state_toset
) {
130 ppsc
->rfoff_reason
&= (~changesource
);
132 if ((changesource
== RF_CHANGE_BY_HW
) &&
133 (ppsc
->b_hwradiooff
)) {
134 ppsc
->b_hwradiooff
= false;
136 if (!ppsc
->rfoff_reason
) {
137 ppsc
->rfoff_reason
= 0;
138 b_actionallowed
= true;
142 if ((changesource
== RF_CHANGE_BY_HW
) &&
143 (!ppsc
->b_hwradiooff
)) {
144 ppsc
->b_hwradiooff
= true;
146 ppsc
->rfoff_reason
|= changesource
;
147 b_actionallowed
= true;
150 ppsc
->rfoff_reason
|= changesource
;
151 b_actionallowed
= true;
154 RT_TRACE(COMP_ERR
, DBG_EMERG
, ("switch case not process\n"));
159 rtlpriv
->cfg
->ops
->set_rf_power_state(hw
, state_toset
);
161 if (!protect_or_not
) {
162 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
163 ppsc
->rfchange_inprogress
= false;
164 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
167 return b_actionallowed
;
169 EXPORT_SYMBOL(stg_rtl_ps_set_rf_state
);
171 static void _rtl_ps_inactive_ps(struct ieee80211_hw
*hw
)
173 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
174 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
175 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
177 ppsc
->b_swrf_processing
= true;
179 if (ppsc
->inactive_pwrstate
== ERFON
&& rtlhal
->interface
== INTF_PCI
) {
180 if ((ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
) &&
181 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
) &&
182 rtlhal
->interface
== INTF_PCI
) {
183 rtlpriv
->intf_ops
->disable_aspm(hw
);
184 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
188 stg_rtl_ps_set_rf_state(hw
, ppsc
->inactive_pwrstate
,
189 RF_CHANGE_BY_IPS
, false);
191 if (ppsc
->inactive_pwrstate
== ERFOFF
&&
192 rtlhal
->interface
== INTF_PCI
) {
193 if (ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
&&
194 !RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
195 rtlpriv
->intf_ops
->enable_aspm(hw
);
196 RT_SET_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
200 ppsc
->b_swrf_processing
= false;
203 void rtl92e_ips_nic_off_wq_callback(void *data
)
205 struct rtl_works
*rtlworks
=
206 container_of_dwork_rtl(data
, struct rtl_works
, ips_nic_off_wq
);
207 struct ieee80211_hw
*hw
= rtlworks
->hw
;
208 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
209 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
210 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
211 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
212 enum rf_pwrstate rtstate
;
214 if (mac
->opmode
!= NL80211_IFTYPE_STATION
) {
215 RT_TRACE(COMP_ERR
, DBG_WARNING
, ("not station return\n"));
222 if (mac
->link_state
> MAC80211_NOLINK
)
225 if (is_hal_stop(rtlhal
))
228 if (rtlpriv
->sec
.being_setkey
)
231 if (rtlpriv
->cfg
->ops
->bt_turn_off_bt_coexist_before_enter_lps
)
232 rtlpriv
->cfg
->ops
->bt_turn_off_bt_coexist_before_enter_lps(hw
);
234 if (ppsc
->b_inactiveps
) {
235 rtstate
= ppsc
->rfpwr_state
;
238 *Do not enter IPS in the following conditions:
239 *(1) RF is already OFF or Sleep
240 *(2) b_swrf_processing (indicates the IPS is still under going)
241 *(3) Connectted (only disconnected can trigger IPS)
242 *(4) IBSS (send Beacon)
243 *(5) AP mode (send Beacon)
244 *(6) monitor mode (rcv packet)
247 if (rtstate
== ERFON
&&
248 !ppsc
->b_swrf_processing
&&
249 (mac
->link_state
== MAC80211_NOLINK
) &&
250 !mac
->act_scanning
) {
251 RT_TRACE(COMP_RF
, DBG_LOUD
,
252 ("IPSEnter(): Turn off RF.\n"));
254 ppsc
->inactive_pwrstate
= ERFOFF
;
255 ppsc
->b_in_powersavemode
= true;
257 /* call before RF off */
258 if (rtlpriv
->cfg
->ops
->get_btc_status())
259 rtlpriv
->btcoexist
.btc_ops
->btc_ips_notify(rtlpriv
,
260 ppsc
->inactive_pwrstate
);
262 /*rtl92e_pci_reset_trx_ring(hw); */
263 _rtl_ps_inactive_ps(hw
);
268 void rtl92e_ips_nic_off(struct ieee80211_hw
*hw
)
270 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
273 *because when link with ap, mac80211 will ask us
274 *to disable nic quickly after scan before linking,
275 *this will cause link failed, so we delay 100ms here
277 queue_delayed_work(rtlpriv
->works
.rtl_wq
,
278 &rtlpriv
->works
.ips_nic_off_wq
, MSECS(100));
281 /* NOTICE: any opmode should exc nic_on, or disable without
282 * nic_on may something wrong, like adhoc TP*/
283 void rtl92e_ips_nic_on(struct ieee80211_hw
*hw
)
285 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
286 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
287 enum rf_pwrstate rtstate
;
289 cancel_delayed_work(&rtlpriv
->works
.ips_nic_off_wq
);
291 spin_lock(&rtlpriv
->locks
.ips_lock
);
292 if (ppsc
->b_inactiveps
) {
293 rtstate
= ppsc
->rfpwr_state
;
295 if (rtstate
!= ERFON
&&
296 !ppsc
->b_swrf_processing
&&
297 ppsc
->rfoff_reason
<= RF_CHANGE_BY_IPS
) {
298 ppsc
->inactive_pwrstate
= ERFON
;
299 ppsc
->b_in_powersavemode
= false;
300 _rtl_ps_inactive_ps(hw
);
301 /* call after RF on */
302 if (rtlpriv
->cfg
->ops
->get_btc_status())
303 rtlpriv
->btcoexist
.btc_ops
->btc_ips_notify(rtlpriv
,
304 ppsc
->inactive_pwrstate
);
307 spin_unlock(&rtlpriv
->locks
.ips_lock
);
313 *Determine if we can set Fw into PS mode
314 *in current condition.Return true if it
317 static bool rtl_get_fwlps_doze(struct ieee80211_hw
*hw
)
319 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
320 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
321 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
324 ps_timediff
= jiffies_to_msecs(jiffies
-
325 ppsc
->last_delaylps_stamp_jiffies
);
327 if (ps_timediff
< 2000) {
328 RT_TRACE(COMP_POWER
, DBG_LOUD
,
329 ("Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n"));
333 if (mac
->link_state
!= MAC80211_LINKED
)
336 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
342 /* Change current and default preamble mode.*/
343 void rtl_lps_set_psmode(struct ieee80211_hw
*hw
, u8 rt_psmode
)
345 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
346 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
347 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
350 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
353 if (mac
->link_state
!= MAC80211_LINKED
)
356 if (ppsc
->dot11_psmode
== rt_psmode
)
359 /* Update power save mode configured. */
360 ppsc
->dot11_psmode
= rt_psmode
;
365 * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
366 * cmd to set Fw into PS mode.
368 * Send H2C fw_pwrmode cmd to Fw to set Fw into Active
369 * mode and set RPWM to turn RF on.
372 if ((ppsc
->b_fwctrl_lps
) && ppsc
->report_linked
) {
373 if (ppsc
->dot11_psmode
== EACTIVE
) {
374 RT_TRACE(COMP_RF
, DBG_DMESG
,
375 ("FW LPS leave ps_mode:%x\n",
378 ppsc
->pwr_mode
= FW_PS_ACTIVE_MODE
;
380 rtlpriv
->cfg
->ops
->set_hw_reg(hw
, HW_VAR_FW_LPS_ACTION
,
381 (u8
*)(&enter_fwlps
));
382 if (ppsc
->p2p_ps_info
.opp_ps
)
383 rtl92e_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
385 if (rtlpriv
->cfg
->ops
->get_btc_status())
386 rtlpriv
->btcoexist
.btc_ops
->btc_lps_notify(rtlpriv
, rt_psmode
);
388 if (rtl_get_fwlps_doze(hw
)) {
389 RT_TRACE(COMP_RF
, DBG_DMESG
,
390 ("FW LPS enter ps_mode:%x\n",
391 ppsc
->fwctrl_psmode
));
392 if (rtlpriv
->cfg
->ops
->get_btc_status())
393 rtlpriv
->btcoexist
.btc_ops
->btc_lps_notify(rtlpriv
, rt_psmode
);
395 ppsc
->pwr_mode
= ppsc
->fwctrl_psmode
;
397 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
398 HW_VAR_FW_LPS_ACTION
,
399 (u8
*)(&enter_fwlps
));
402 /* Reset the power save related parameters. */
403 ppsc
->dot11_psmode
= EACTIVE
;
409 /*Enter the leisure power save mode.*/
410 void rtl92e_lps_enter(struct ieee80211_hw
*hw
)
412 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
413 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
414 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
417 if (!ppsc
->b_fwctrl_lps
)
420 if (rtlpriv
->sec
.being_setkey
)
423 if (rtlpriv
->link_info
.b_busytraffic
)
426 /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
427 if (mac
->cnt_after_linked
< 5)
430 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
433 if (mac
->link_state
!= MAC80211_LINKED
)
436 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
438 /* Idle for a while if we connect to AP a while ago. */
439 if (mac
->cnt_after_linked
>= 2) {
440 if (ppsc
->dot11_psmode
== EACTIVE
) {
441 RT_TRACE(COMP_POWER
, DBG_LOUD
,
442 ("Enter 802.11 power save mode...\n"));
444 rtl_lps_set_psmode(hw
, EAUTOPS
);
448 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
450 EXPORT_SYMBOL(rtl92e_lps_enter
);
452 /*Leave the leisure power save mode.*/
453 void rtl92e_lps_leave(struct ieee80211_hw
*hw
)
455 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
456 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
457 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
460 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
462 if (ppsc
->b_fwctrl_lps
) {
463 if (ppsc
->dot11_psmode
!= EACTIVE
) {
464 if (ppsc
->reg_rfps_level
& RT_RF_LPS_LEVEL_ASPM
&&
465 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
) &&
466 rtlhal
->interface
== INTF_PCI
) {
467 rtlpriv
->intf_ops
->disable_aspm(hw
);
468 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
471 RT_TRACE(COMP_POWER
, DBG_LOUD
,
472 ("Busy Traffic,Leave 802.11 power save..\n"));
474 rtl_lps_set_psmode(hw
, EACTIVE
);
477 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
479 EXPORT_SYMBOL(rtl92e_lps_leave
);
482 void rtl92e_swlps_beacon(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
484 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
485 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
486 struct ieee80211_hdr
*hdr
= (void *)data
;
487 struct ieee80211_tim_ie
*tim_ie
;
493 if (mac
->opmode
!= NL80211_IFTYPE_STATION
)
496 if (!rtlpriv
->psc
.b_swctrl_lps
)
499 if (rtlpriv
->mac80211
.link_state
!= MAC80211_LINKED
)
502 if (!rtlpriv
->psc
.sw_ps_enabled
)
505 if (rtlpriv
->psc
.b_fwctrl_lps
)
508 if (likely(!(hw
->conf
.flags
& IEEE80211_CONF_PS
)))
511 /* check if this really is a beacon */
512 if (!ieee80211_is_beacon(hdr
->frame_control
))
515 /* min. beacon length + FCS_LEN */
516 if (len
<= 40 + FCS_LEN
)
519 /* and only beacons from the associated BSSID, please */
520 if (!ether_addr_equal(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
523 rtlpriv
->psc
.last_beacon
= jiffies
;
525 tim
= rtl92e_find_ie(data
, len
- FCS_LEN
, WLAN_EID_TIM
);
529 if (tim
[1] < sizeof(*tim_ie
))
533 tim_ie
= (struct ieee80211_tim_ie
*)&tim
[2];
535 if (!WARN_ON_ONCE(!hw
->conf
.ps_dtim_period
))
536 rtlpriv
->psc
.dtim_counter
= tim_ie
->dtim_count
;
538 /* Check whenever the PHY can be turned off again. */
540 /* 1. What about buffered unicast traffic for our AID? */
541 u_buffed
= ieee80211_check_tim(tim_ie
, tim_len
,
542 rtlpriv
->mac80211
.assoc_id
);
544 /* 2. Maybe the AP wants to send multicast/broadcast data? */
545 m_buffed
= tim_ie
->bitmap_ctrl
& 0x01;
546 rtlpriv
->psc
.multi_buffered
= m_buffed
;
548 /* unicast will process by mac80211 through
549 * set ~IEEE80211_CONF_PS, So we just check
550 * multicast frames here */
551 if (!m_buffed
) {/*&&) { !rtlpriv->psc.tx_doing) { */
552 /* back to low-power land. and delay is
553 * prevent null power save frame tx fail */
554 queue_delayed_work(rtlpriv
->works
.rtl_wq
,
555 &rtlpriv
->works
.ps_work
, MSECS(5));
557 RT_TRACE(COMP_POWER
, DBG_DMESG
,
558 ("u_bufferd: %x, m_buffered: %x\n",
559 u_buffed
, m_buffed
));
563 void rtl92e_swlps_rf_awake(struct ieee80211_hw
*hw
)
565 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
566 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
567 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
570 if (!rtlpriv
->psc
.b_swctrl_lps
)
572 if (mac
->link_state
!= MAC80211_LINKED
)
575 if (ppsc
->reg_rfps_level
& RT_RF_LPS_LEVEL_ASPM
&&
576 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
577 rtlpriv
->intf_ops
->disable_aspm(hw
);
578 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
581 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
582 stg_rtl_ps_set_rf_state(hw
, ERFON
, RF_CHANGE_BY_PS
, false);
583 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
586 void rtl92e_swlps_rfon_wq_callback(void *data
)
588 struct rtl_works
*rtlworks
=
589 container_of_dwork_rtl(data
, struct rtl_works
, ps_rfon_wq
);
590 struct ieee80211_hw
*hw
= rtlworks
->hw
;
592 rtl92e_swlps_rf_awake(hw
);
595 void rtl92e_swlps_rf_sleep(struct ieee80211_hw
*hw
)
597 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
598 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
599 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
603 if (!rtlpriv
->psc
.sw_ps_enabled
)
606 if ((rtlpriv
->sec
.being_setkey
) ||
607 (mac
->opmode
== NL80211_IFTYPE_ADHOC
))
610 /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
611 if ((mac
->link_state
!= MAC80211_LINKED
) || (mac
->cnt_after_linked
< 5))
614 if (rtlpriv
->link_info
.b_busytraffic
)
617 spin_lock(&rtlpriv
->locks
.rf_ps_lock
);
618 if (rtlpriv
->psc
.rfchange_inprogress
) {
619 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
622 spin_unlock(&rtlpriv
->locks
.rf_ps_lock
);
624 spin_lock_irqsave(&rtlpriv
->locks
.lps_lock
, flag
);
625 stg_rtl_ps_set_rf_state(hw
, ERFSLEEP
, RF_CHANGE_BY_PS
, false);
626 spin_unlock_irqrestore(&rtlpriv
->locks
.lps_lock
, flag
);
628 if (ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
&&
629 !RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
630 rtlpriv
->intf_ops
->enable_aspm(hw
);
631 RT_SET_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
634 /* here is power save alg, when this beacon is DTIM
635 * we will set sleep time to dtim_period * n;
636 * when this beacon is not DTIM, we will set sleep
637 * time to sleep_intv = rtlpriv->psc.dtim_counter or
638 * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
640 if (rtlpriv
->psc
.dtim_counter
== 0) {
641 if (hw
->conf
.ps_dtim_period
== 1)
642 sleep_intv
= hw
->conf
.ps_dtim_period
* 2;
644 sleep_intv
= hw
->conf
.ps_dtim_period
;
646 sleep_intv
= rtlpriv
->psc
.dtim_counter
;
649 if (sleep_intv
> MAX_SW_LPS_SLEEP_INTV
)
650 sleep_intv
= MAX_SW_LPS_SLEEP_INTV
;
652 /* this print should always be dtim_conter = 0 &
653 * sleep = dtim_period, that meaons, we should
654 * awake before every dtim */
655 RT_TRACE(COMP_POWER
, DBG_DMESG
,
656 ("dtim_counter:%x will sleep :%d beacon_intv\n",
657 rtlpriv
->psc
.dtim_counter
, sleep_intv
));
659 /* we tested that 40ms is enough for sw & hw sw delay */
660 queue_delayed_work(rtlpriv
->works
.rtl_wq
, &rtlpriv
->works
.ps_rfon_wq
,
661 MSECS(sleep_intv
*mac
->vif
->bss_conf
.beacon_int
-40));
665 void rtl92e_swlps_wq_callback(void *data
)
667 struct rtl_works
*rtlworks
=
668 container_of_dwork_rtl(data
, struct rtl_works
, ps_work
);
669 struct ieee80211_hw
*hw
= rtlworks
->hw
;
670 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
673 ps
= (hw
->conf
.flags
& IEEE80211_CONF_PS
);
675 /* we can sleep after ps null send ok */
676 if (rtlpriv
->psc
.state_inap
) {
677 rtl92e_swlps_rf_sleep(hw
);
679 if (rtlpriv
->psc
.state
&& !ps
) {
680 rtlpriv
->psc
.sleep_ms
=
681 jiffies_to_msecs(jiffies
-
682 rtlpriv
->psc
.last_action
);
686 rtlpriv
->psc
.last_slept
= jiffies
;
688 rtlpriv
->psc
.last_action
= jiffies
;
689 rtlpriv
->psc
.state
= ps
;
693 static void rtl_p2p_noa_ie(struct ieee80211_hw
*hw
, void *data
,
696 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
697 struct ieee80211_mgmt
*mgmt
= (void *)data
;
698 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
701 static u8 p2p_oui_ie_type
[4] = {0x50, 0x6f, 0x9a, 0x09};
702 u8 noa_num
, index
, i
, noa_index
= 0;
703 bool find_p2p_ie
= false , find_p2p_ps_ie
= false;
704 pos
= (u8
*)mgmt
->u
.beacon
.variable
;
708 while (pos
+ 1 < end
) {
709 if (pos
+ 2 + pos
[1] > end
)
712 if (pos
[0] == 221 && pos
[1] > 4) {
713 if (memcmp(&pos
[2], p2p_oui_ie_type
, 4) == 0) {
725 while (ie
+ 1 < end
) {
726 noa_len
= READEF2BYTE((__le16
*)&ie
[1]);
727 if (ie
+ 3 + ie
[1] > end
)
731 find_p2p_ps_ie
= true;
732 if ((noa_len
- 2) % 13 != 0) {
733 RT_TRACE(COMP_INIT
, DBG_LOUD
,
734 ("P2P notice of absence: invalid length%d\n",
738 noa_num
= (noa_len
- 2) / 13;
741 if (rtlpriv
->psc
.p2p_ps_info
.p2p_ps_mode
==
742 P2P_PS_NONE
|| noa_index
!= p2pinfo
->noa_index
) {
743 RT_TRACE(COMP_FW
, DBG_LOUD
,
744 ("update NOA ie.\n"));
745 p2pinfo
->noa_index
= noa_index
;
746 p2pinfo
->opp_ps
= (ie
[4] >> 7);
747 p2pinfo
->ctwindow
= ie
[4] & 0x7F;
748 p2pinfo
->noa_num
= noa_num
;
750 for (i
= 0; i
< noa_num
; i
++) {
751 p2pinfo
->noa_count_type
[i
] =
752 READEF1BYTE(ie
+index
);
754 p2pinfo
->noa_duration
[i
] =
755 READEF4BYTE((__le32
*)ie
+index
);
757 p2pinfo
->noa_interval
[i
] =
758 READEF4BYTE((__le32
*)ie
+index
);
760 p2pinfo
->noa_start_time
[i
] =
761 READEF4BYTE((__le32
*)ie
+index
);
765 if (p2pinfo
->opp_ps
== 1) {
766 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
767 /* Driver should wait LPS
768 * entering CTWindow*/
769 if (rtlpriv
->psc
.b_fw_current_inpsmode
) {
770 rtl92e_p2p_ps_cmd(hw
,
773 } else if (p2pinfo
->noa_num
> 0) {
774 p2pinfo
->p2p_ps_mode
= P2P_PS_NOA
;
775 rtl92e_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
776 } else if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
777 rtl92e_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
787 if ((p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) &&
789 rtl92e_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
793 static void rtl_p2p_action_ie(struct ieee80211_hw
*hw
, void *data
,
796 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
797 struct ieee80211_mgmt
*mgmt
= (void *)data
;
798 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
799 bool find_p2p_ie
= false, find_p2p_ps_ie
= false;
800 u8 noa_num
, index
, i
, noa_index
= 0;
803 static u8 p2p_oui_ie_type
[4] = {0x50, 0x6f, 0x9a, 0x09};
805 pos
= (u8
*)&mgmt
->u
.action
.category
;
809 if (pos
[0] == 0x7f) {
810 if (memcmp(&pos
[1], p2p_oui_ie_type
, 4) == 0)
818 RT_TRACE(COMP_FW
, DBG_LOUD
, ("action frame find P2P IE.\n"));
820 while (ie
+ 1 < end
) {
821 noa_len
= READEF2BYTE((__le16
*)&ie
[1]);
822 if (ie
+ 3 + ie
[1] > end
)
826 RT_TRACE(COMP_FW
, DBG_LOUD
, ("find NOA IE\n"));
827 RT_PRINT_DATA(rtlpriv
, COMP_FW
, DBG_LOUD
, "noa ie ",
829 find_p2p_ps_ie
= true;
830 if ((noa_len
- 2) % 13 != 0) {
831 RT_TRACE(COMP_FW
, DBG_LOUD
,
832 ("P2P notice of absence: invalid length%d\n",
836 noa_num
= (noa_len
- 2) / 13;
839 if (rtlpriv
->psc
.p2p_ps_info
.p2p_ps_mode
==
841 noa_index
!= p2pinfo
->noa_index
) {
842 p2pinfo
->noa_index
= noa_index
;
843 p2pinfo
->opp_ps
= (ie
[4] >> 7);
844 p2pinfo
->ctwindow
= ie
[4] & 0x7F;
845 p2pinfo
->noa_num
= noa_num
;
847 for (i
= 0; i
< noa_num
; i
++) {
848 p2pinfo
->noa_count_type
[i
] =
849 READEF1BYTE(ie
+index
);
851 p2pinfo
->noa_duration
[i
] =
852 READEF4BYTE((__le32
*)ie
+index
);
854 p2pinfo
->noa_interval
[i
] =
855 READEF4BYTE((__le32
*)ie
+index
);
857 p2pinfo
->noa_start_time
[i
] =
858 READEF4BYTE((__le32
*)ie
+index
);
862 if (p2pinfo
->opp_ps
== 1) {
863 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
864 /* Driver should wait LPS
865 * entering CTWindow */
866 if (rtlpriv
->psc
.b_fw_current_inpsmode
) {
867 rtl92e_p2p_ps_cmd(hw
,
870 } else if (p2pinfo
->noa_num
> 0) {
871 p2pinfo
->p2p_ps_mode
= P2P_PS_NOA
;
872 rtl92e_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
873 } else if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
874 rtl92e_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
884 void rtl92e_p2p_ps_cmd(struct ieee80211_hw
*hw
, u8 p2p_ps_state
)
886 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
887 struct rtl_ps_ctl
*rtlps
= rtl_psc(rtl_priv(hw
));
888 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
890 RT_TRACE(COMP_FW
, DBG_LOUD
, ("p2p state %x\n", p2p_ps_state
));
891 switch (p2p_ps_state
) {
893 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
894 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
895 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
896 (u8
*)(&p2p_ps_state
));
898 p2pinfo
->noa_index
= 0;
899 p2pinfo
->ctwindow
= 0;
901 p2pinfo
->noa_num
= 0;
902 p2pinfo
->p2p_ps_mode
= P2P_PS_NONE
;
903 if (rtlps
->b_fw_current_inpsmode
) {
904 if (rtlps
->smart_ps
== 0) {
906 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
907 HW_VAR_H2C_FW_PWRMODE
,
908 (u8
*)(&rtlps
->pwr_mode
));
913 if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
914 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
916 if (p2pinfo
->ctwindow
> 0) {
917 if (rtlps
->smart_ps
!= 0) {
919 rtlpriv
->cfg
->ops
->set_hw_reg(
920 hw
, HW_VAR_H2C_FW_PWRMODE
,
921 (u8
*)(&rtlps
->pwr_mode
));
924 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
925 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
926 (u8
*)(&p2p_ps_state
));
930 case P2P_PS_SCAN_DONE
:
931 case P2P_PS_ALLSTASLEEP
:
932 if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
933 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
934 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
935 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
936 (u8
*)(&p2p_ps_state
));
942 RT_TRACE(COMP_FW
, DBG_LOUD
, (" ctwindow %x oppps %x\n",
943 p2pinfo
->ctwindow
, p2pinfo
->opp_ps
));
944 RT_TRACE(COMP_FW
, DBG_LOUD
,
945 ("count %x duration %x index %x interval %x start time %x noa num %x\n",
946 p2pinfo
->noa_count_type
[0],
947 p2pinfo
->noa_duration
[0],
949 p2pinfo
->noa_interval
[0],
950 p2pinfo
->noa_start_time
[0],
952 RT_TRACE(COMP_FW
, DBG_LOUD
, ("end\n"));
955 void rtl92e_p2p_info(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
957 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
958 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
959 struct ieee80211_hdr
*hdr
= (void *)data
;
963 if (mac
->link_state
!= MAC80211_LINKED
)
965 /* min. beacon length + FCS_LEN */
966 if (len
<= 40 + FCS_LEN
)
969 /* and only beacons from the associated BSSID, please */
970 if (!ether_addr_equal(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
973 /* check if this really is a beacon */
974 if (!(ieee80211_is_beacon(hdr
->frame_control
) ||
975 ieee80211_is_probe_resp(hdr
->frame_control
) ||
976 ieee80211_is_action(hdr
->frame_control
)))
979 if (ieee80211_is_action(hdr
->frame_control
))
980 rtl_p2p_action_ie(hw
, data
, len
- FCS_LEN
);
982 rtl_p2p_noa_ie(hw
, data
, len
- FCS_LEN
);