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 * 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 *****************************************************************************/
30 #include <linux/export.h>
35 bool rtl_ps_enable_nic(struct ieee80211_hw
*hw
)
37 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
38 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
39 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
41 /*<1> reset trx ring */
42 if (rtlhal
->interface
== INTF_PCI
)
43 rtlpriv
->intf_ops
->reset_trx_ring(hw
);
45 if (is_hal_stop(rtlhal
))
46 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
47 "Driver is already down!\n");
49 /*<2> Enable Adapter */
50 if (rtlpriv
->cfg
->ops
->hw_init(hw
))
52 RT_CLEAR_PS_LEVEL(ppsc
, RT_RF_OFF_LEVL_HALT_NIC
);
54 /*<3> Enable Interrupt */
55 rtlpriv
->cfg
->ops
->enable_interrupt(hw
);
58 rtl_watch_dog_timer_callback((unsigned long)hw
);
62 EXPORT_SYMBOL(rtl_ps_enable_nic
);
64 bool rtl_ps_disable_nic(struct ieee80211_hw
*hw
)
66 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
68 /*<1> Stop all timer */
69 rtl_deinit_deferred_work(hw
);
71 /*<2> Disable Interrupt */
72 rtlpriv
->cfg
->ops
->disable_interrupt(hw
);
73 tasklet_kill(&rtlpriv
->works
.irq_tasklet
);
75 /*<3> Disable Adapter */
76 rtlpriv
->cfg
->ops
->hw_disable(hw
);
80 EXPORT_SYMBOL(rtl_ps_disable_nic
);
82 bool rtl_ps_set_rf_state(struct ieee80211_hw
*hw
,
83 enum rf_pwrstate state_toset
,
86 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
87 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
88 bool actionallowed
= false;
90 switch (state_toset
) {
92 ppsc
->rfoff_reason
&= (~changesource
);
94 if ((changesource
== RF_CHANGE_BY_HW
) &&
96 ppsc
->hwradiooff
= false;
99 if (!ppsc
->rfoff_reason
) {
100 ppsc
->rfoff_reason
= 0;
101 actionallowed
= true;
108 if ((changesource
== RF_CHANGE_BY_HW
) && !ppsc
->hwradiooff
) {
109 ppsc
->hwradiooff
= true;
112 ppsc
->rfoff_reason
|= changesource
;
113 actionallowed
= true;
117 ppsc
->rfoff_reason
|= changesource
;
118 actionallowed
= true;
122 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
123 "switch case not processed\n");
128 rtlpriv
->cfg
->ops
->set_rf_power_state(hw
, state_toset
);
130 return actionallowed
;
132 EXPORT_SYMBOL(rtl_ps_set_rf_state
);
134 static void _rtl_ps_inactive_ps(struct ieee80211_hw
*hw
)
136 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
137 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
138 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
140 ppsc
->swrf_processing
= true;
142 if (ppsc
->inactive_pwrstate
== ERFON
&&
143 rtlhal
->interface
== INTF_PCI
) {
144 if ((ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
) &&
145 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
) &&
146 rtlhal
->interface
== INTF_PCI
) {
147 rtlpriv
->intf_ops
->disable_aspm(hw
);
148 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
152 rtl_ps_set_rf_state(hw
, ppsc
->inactive_pwrstate
, RF_CHANGE_BY_IPS
);
154 if (ppsc
->inactive_pwrstate
== ERFOFF
&&
155 rtlhal
->interface
== INTF_PCI
) {
156 if (ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
&&
157 !RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
158 rtlpriv
->intf_ops
->enable_aspm(hw
);
159 RT_SET_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
163 ppsc
->swrf_processing
= false;
166 void rtl_ips_nic_off_wq_callback(void *data
)
168 struct rtl_works
*rtlworks
=
169 container_of_dwork_rtl(data
, struct rtl_works
, ips_nic_off_wq
);
170 struct ieee80211_hw
*hw
= rtlworks
->hw
;
171 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
172 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
173 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
174 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
175 enum rf_pwrstate rtstate
;
177 if (mac
->opmode
!= NL80211_IFTYPE_STATION
) {
178 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
179 "not station return\n");
186 if (mac
->link_state
> MAC80211_NOLINK
)
189 if (is_hal_stop(rtlhal
))
192 if (rtlpriv
->sec
.being_setkey
)
195 if (rtlpriv
->cfg
->ops
->bt_coex_off_before_lps
)
196 rtlpriv
->cfg
->ops
->bt_coex_off_before_lps(hw
);
198 if (ppsc
->inactiveps
) {
199 rtstate
= ppsc
->rfpwr_state
;
202 *Do not enter IPS in the following conditions:
203 *(1) RF is already OFF or Sleep
204 *(2) swrf_processing (indicates the IPS is still under going)
205 *(3) Connectted (only disconnected can trigger IPS)
206 *(4) IBSS (send Beacon)
207 *(5) AP mode (send Beacon)
208 *(6) monitor mode (rcv packet)
211 if (rtstate
== ERFON
&&
212 !ppsc
->swrf_processing
&&
213 (mac
->link_state
== MAC80211_NOLINK
) &&
214 !mac
->act_scanning
) {
215 RT_TRACE(rtlpriv
, COMP_RF
, DBG_TRACE
,
216 "IPSEnter(): Turn off RF\n");
218 ppsc
->inactive_pwrstate
= ERFOFF
;
219 ppsc
->in_powersavemode
= true;
221 /*rtl_pci_reset_trx_ring(hw); */
222 _rtl_ps_inactive_ps(hw
);
227 void rtl_ips_nic_off(struct ieee80211_hw
*hw
)
229 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
232 *because when link with ap, mac80211 will ask us
233 *to disable nic quickly after scan before linking,
234 *this will cause link failed, so we delay 100ms here
236 queue_delayed_work(rtlpriv
->works
.rtl_wq
,
237 &rtlpriv
->works
.ips_nic_off_wq
, MSECS(100));
240 /* NOTICE: any opmode should exc nic_on, or disable without
241 * nic_on may something wrong, like adhoc TP
243 void rtl_ips_nic_on(struct ieee80211_hw
*hw
)
245 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
246 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
247 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
248 enum rf_pwrstate rtstate
;
251 if (mac
->opmode
!= NL80211_IFTYPE_STATION
)
254 spin_lock_irqsave(&rtlpriv
->locks
.ips_lock
, flags
);
256 if (ppsc
->inactiveps
) {
257 rtstate
= ppsc
->rfpwr_state
;
259 if (rtstate
!= ERFON
&&
260 !ppsc
->swrf_processing
&&
261 ppsc
->rfoff_reason
<= RF_CHANGE_BY_IPS
) {
263 ppsc
->inactive_pwrstate
= ERFON
;
264 ppsc
->in_powersavemode
= false;
266 _rtl_ps_inactive_ps(hw
);
270 spin_unlock_irqrestore(&rtlpriv
->locks
.ips_lock
, flags
);
272 EXPORT_SYMBOL_GPL(rtl_ips_nic_on
);
277 *Determine if we can set Fw into PS mode
278 *in current condition.Return TRUE if it
281 static bool rtl_get_fwlps_doze(struct ieee80211_hw
*hw
)
283 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
284 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
285 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
288 ps_timediff
= jiffies_to_msecs(jiffies
-
289 ppsc
->last_delaylps_stamp_jiffies
);
291 if (ps_timediff
< 2000) {
292 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
,
293 "Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n");
297 if (mac
->link_state
!= MAC80211_LINKED
)
300 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
306 /* Change current and default preamble mode.*/
307 static void rtl_lps_set_psmode(struct ieee80211_hw
*hw
, u8 rt_psmode
)
309 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
310 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
311 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
314 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
317 if (mac
->link_state
!= MAC80211_LINKED
)
320 if (ppsc
->dot11_psmode
== rt_psmode
)
323 /* Update power save mode configured. */
324 ppsc
->dot11_psmode
= rt_psmode
;
329 * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
330 * cmd to set Fw into PS mode.
332 * Send H2C fw_pwrmode cmd to Fw to set Fw into Active
333 * mode and set RPWM to turn RF on.
336 if ((ppsc
->fwctrl_lps
) && ppsc
->report_linked
) {
337 if (ppsc
->dot11_psmode
== EACTIVE
) {
338 RT_TRACE(rtlpriv
, COMP_RF
, DBG_DMESG
,
339 "FW LPS leave ps_mode:%x\n",
342 ppsc
->pwr_mode
= FW_PS_ACTIVE_MODE
;
344 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
345 HW_VAR_FW_LPS_ACTION
,
346 (u8
*)(&enter_fwlps
));
347 if (ppsc
->p2p_ps_info
.opp_ps
)
348 rtl_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
351 if (rtl_get_fwlps_doze(hw
)) {
352 RT_TRACE(rtlpriv
, COMP_RF
, DBG_DMESG
,
353 "FW LPS enter ps_mode:%x\n",
354 ppsc
->fwctrl_psmode
);
356 ppsc
->pwr_mode
= ppsc
->fwctrl_psmode
;
358 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
359 HW_VAR_FW_LPS_ACTION
,
360 (u8
*)(&enter_fwlps
));
363 /* Reset the power save related parameters. */
364 ppsc
->dot11_psmode
= EACTIVE
;
370 /*Enter the leisure power save mode.*/
371 void rtl_lps_enter(struct ieee80211_hw
*hw
)
373 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
374 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
375 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
377 if (!ppsc
->fwctrl_lps
)
380 if (rtlpriv
->sec
.being_setkey
)
383 if (rtlpriv
->link_info
.busytraffic
)
386 /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
387 if (mac
->cnt_after_linked
< 5)
390 if (mac
->opmode
== NL80211_IFTYPE_ADHOC
)
393 if (mac
->link_state
!= MAC80211_LINKED
)
396 mutex_lock(&rtlpriv
->locks
.ps_mutex
);
398 /* Idle for a while if we connect to AP a while ago. */
399 if (mac
->cnt_after_linked
>= 2) {
400 if (ppsc
->dot11_psmode
== EACTIVE
) {
401 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
,
402 "Enter 802.11 power save mode...\n");
404 rtl_lps_set_psmode(hw
, EAUTOPS
);
408 mutex_unlock(&rtlpriv
->locks
.ps_mutex
);
411 /*Leave the leisure power save mode.*/
412 void rtl_lps_leave(struct ieee80211_hw
*hw
)
414 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
415 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
416 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
418 mutex_lock(&rtlpriv
->locks
.ps_mutex
);
420 if (ppsc
->fwctrl_lps
) {
421 if (ppsc
->dot11_psmode
!= EACTIVE
) {
424 rtlpriv
->cfg
->ops
->enable_interrupt(hw
);
426 if (ppsc
->reg_rfps_level
& RT_RF_LPS_LEVEL_ASPM
&&
427 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
) &&
428 rtlhal
->interface
== INTF_PCI
) {
429 rtlpriv
->intf_ops
->disable_aspm(hw
);
430 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
433 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
,
434 "Busy Traffic,Leave 802.11 power save..\n");
436 rtl_lps_set_psmode(hw
, EACTIVE
);
439 mutex_unlock(&rtlpriv
->locks
.ps_mutex
);
443 void rtl_swlps_beacon(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
445 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
446 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
447 struct ieee80211_hdr
*hdr
= data
;
448 struct ieee80211_tim_ie
*tim_ie
;
454 if (mac
->opmode
!= NL80211_IFTYPE_STATION
)
457 if (!rtlpriv
->psc
.swctrl_lps
)
460 if (rtlpriv
->mac80211
.link_state
!= MAC80211_LINKED
)
463 if (!rtlpriv
->psc
.sw_ps_enabled
)
466 if (rtlpriv
->psc
.fwctrl_lps
)
469 if (likely(!(hw
->conf
.flags
& IEEE80211_CONF_PS
)))
472 /* check if this really is a beacon */
473 if (!ieee80211_is_beacon(hdr
->frame_control
))
476 /* min. beacon length + FCS_LEN */
477 if (len
<= 40 + FCS_LEN
)
480 /* and only beacons from the associated BSSID, please */
481 if (!ether_addr_equal(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
484 rtlpriv
->psc
.last_beacon
= jiffies
;
486 tim
= rtl_find_ie(data
, len
- FCS_LEN
, WLAN_EID_TIM
);
490 if (tim
[1] < sizeof(*tim_ie
))
494 tim_ie
= (struct ieee80211_tim_ie
*) &tim
[2];
496 if (!WARN_ON_ONCE(!hw
->conf
.ps_dtim_period
))
497 rtlpriv
->psc
.dtim_counter
= tim_ie
->dtim_count
;
499 /* Check whenever the PHY can be turned off again. */
501 /* 1. What about buffered unicast traffic for our AID? */
502 u_buffed
= ieee80211_check_tim(tim_ie
, tim_len
,
503 rtlpriv
->mac80211
.assoc_id
);
505 /* 2. Maybe the AP wants to send multicast/broadcast data? */
506 m_buffed
= tim_ie
->bitmap_ctrl
& 0x01;
507 rtlpriv
->psc
.multi_buffered
= m_buffed
;
509 /* unicast will process by mac80211 through
510 * set ~IEEE80211_CONF_PS, So we just check
511 * multicast frames here */
513 /* back to low-power land. and delay is
514 * prevent null power save frame tx fail */
515 queue_delayed_work(rtlpriv
->works
.rtl_wq
,
516 &rtlpriv
->works
.ps_work
, MSECS(5));
518 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_DMESG
,
519 "u_bufferd: %x, m_buffered: %x\n", u_buffed
, m_buffed
);
522 EXPORT_SYMBOL_GPL(rtl_swlps_beacon
);
524 void rtl_swlps_rf_awake(struct ieee80211_hw
*hw
)
526 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
527 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
528 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
530 if (!rtlpriv
->psc
.swctrl_lps
)
532 if (mac
->link_state
!= MAC80211_LINKED
)
535 if (ppsc
->reg_rfps_level
& RT_RF_LPS_LEVEL_ASPM
&&
536 RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
537 rtlpriv
->intf_ops
->disable_aspm(hw
);
538 RT_CLEAR_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
541 mutex_lock(&rtlpriv
->locks
.ps_mutex
);
542 rtl_ps_set_rf_state(hw
, ERFON
, RF_CHANGE_BY_PS
);
543 mutex_unlock(&rtlpriv
->locks
.ps_mutex
);
546 void rtl_swlps_rfon_wq_callback(void *data
)
548 struct rtl_works
*rtlworks
=
549 container_of_dwork_rtl(data
, struct rtl_works
, ps_rfon_wq
);
550 struct ieee80211_hw
*hw
= rtlworks
->hw
;
552 rtl_swlps_rf_awake(hw
);
555 void rtl_swlps_rf_sleep(struct ieee80211_hw
*hw
)
557 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
558 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
559 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
562 if (!rtlpriv
->psc
.sw_ps_enabled
)
565 if ((rtlpriv
->sec
.being_setkey
) ||
566 (mac
->opmode
== NL80211_IFTYPE_ADHOC
))
569 /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
570 if ((mac
->link_state
!= MAC80211_LINKED
) || (mac
->cnt_after_linked
< 5))
573 if (rtlpriv
->link_info
.busytraffic
)
576 mutex_lock(&rtlpriv
->locks
.ps_mutex
);
577 rtl_ps_set_rf_state(hw
, ERFSLEEP
, RF_CHANGE_BY_PS
);
578 mutex_unlock(&rtlpriv
->locks
.ps_mutex
);
580 if (ppsc
->reg_rfps_level
& RT_RF_OFF_LEVL_ASPM
&&
581 !RT_IN_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
)) {
582 rtlpriv
->intf_ops
->enable_aspm(hw
);
583 RT_SET_PS_LEVEL(ppsc
, RT_PS_LEVEL_ASPM
);
586 /* here is power save alg, when this beacon is DTIM
587 * we will set sleep time to dtim_period * n;
588 * when this beacon is not DTIM, we will set sleep
589 * time to sleep_intv = rtlpriv->psc.dtim_counter or
590 * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
592 if (rtlpriv
->psc
.dtim_counter
== 0) {
593 if (hw
->conf
.ps_dtim_period
== 1)
594 sleep_intv
= hw
->conf
.ps_dtim_period
* 2;
596 sleep_intv
= hw
->conf
.ps_dtim_period
;
598 sleep_intv
= rtlpriv
->psc
.dtim_counter
;
601 if (sleep_intv
> MAX_SW_LPS_SLEEP_INTV
)
602 sleep_intv
= MAX_SW_LPS_SLEEP_INTV
;
604 /* this print should always be dtim_conter = 0 &
605 * sleep = dtim_period, that meaons, we should
606 * awake before every dtim */
607 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_DMESG
,
608 "dtim_counter:%x will sleep :%d beacon_intv\n",
609 rtlpriv
->psc
.dtim_counter
, sleep_intv
);
611 /* we tested that 40ms is enough for sw & hw sw delay */
612 queue_delayed_work(rtlpriv
->works
.rtl_wq
, &rtlpriv
->works
.ps_rfon_wq
,
613 MSECS(sleep_intv
* mac
->vif
->bss_conf
.beacon_int
- 40));
616 void rtl_lps_change_work_callback(struct work_struct
*work
)
618 struct rtl_works
*rtlworks
=
619 container_of(work
, struct rtl_works
, lps_change_work
);
620 struct ieee80211_hw
*hw
= rtlworks
->hw
;
621 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
623 if (rtlpriv
->enter_ps
)
628 EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback
);
630 void rtl_swlps_wq_callback(void *data
)
632 struct rtl_works
*rtlworks
= container_of_dwork_rtl(data
,
635 struct ieee80211_hw
*hw
= rtlworks
->hw
;
636 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
639 ps
= (hw
->conf
.flags
& IEEE80211_CONF_PS
);
641 /* we can sleep after ps null send ok */
642 if (rtlpriv
->psc
.state_inap
) {
643 rtl_swlps_rf_sleep(hw
);
645 if (rtlpriv
->psc
.state
&& !ps
) {
646 rtlpriv
->psc
.sleep_ms
= jiffies_to_msecs(jiffies
-
647 rtlpriv
->psc
.last_action
);
651 rtlpriv
->psc
.last_slept
= jiffies
;
653 rtlpriv
->psc
.last_action
= jiffies
;
654 rtlpriv
->psc
.state
= ps
;
658 static void rtl_p2p_noa_ie(struct ieee80211_hw
*hw
, void *data
,
661 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
662 struct ieee80211_mgmt
*mgmt
= (void *)data
;
663 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
666 static u8 p2p_oui_ie_type
[4] = {0x50, 0x6f, 0x9a, 0x09};
667 u8 noa_num
, index
, i
, noa_index
= 0;
668 bool find_p2p_ie
= false , find_p2p_ps_ie
= false;
669 pos
= (u8
*)mgmt
->u
.beacon
.variable
;
673 while (pos
+ 1 < end
) {
674 if (pos
+ 2 + pos
[1] > end
)
677 if (pos
[0] == 221 && pos
[1] > 4) {
678 if (memcmp(&pos
[2], p2p_oui_ie_type
, 4) == 0) {
690 while (ie
+ 1 < end
) {
691 noa_len
= READEF2BYTE((__le16
*)&ie
[1]);
692 if (ie
+ 3 + ie
[1] > end
)
696 find_p2p_ps_ie
= true;
697 if ((noa_len
- 2) % 13 != 0) {
698 RT_TRACE(rtlpriv
, COMP_INIT
, DBG_LOUD
,
699 "P2P notice of absence: invalid length.%d\n",
703 noa_num
= (noa_len
- 2) / 13;
706 if (rtlpriv
->psc
.p2p_ps_info
.p2p_ps_mode
==
707 P2P_PS_NONE
|| noa_index
!= p2pinfo
->noa_index
) {
708 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
710 p2pinfo
->noa_index
= noa_index
;
711 p2pinfo
->opp_ps
= (ie
[4] >> 7);
712 p2pinfo
->ctwindow
= ie
[4] & 0x7F;
713 p2pinfo
->noa_num
= noa_num
;
715 for (i
= 0; i
< noa_num
; i
++) {
716 p2pinfo
->noa_count_type
[i
] =
717 READEF1BYTE(ie
+index
);
719 p2pinfo
->noa_duration
[i
] =
720 READEF4BYTE((__le32
*)ie
+index
);
722 p2pinfo
->noa_interval
[i
] =
723 READEF4BYTE((__le32
*)ie
+index
);
725 p2pinfo
->noa_start_time
[i
] =
726 READEF4BYTE((__le32
*)ie
+index
);
730 if (p2pinfo
->opp_ps
== 1) {
731 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
732 /* Driver should wait LPS entering
735 if (rtlpriv
->psc
.fw_current_inpsmode
)
738 } else if (p2pinfo
->noa_num
> 0) {
739 p2pinfo
->p2p_ps_mode
= P2P_PS_NOA
;
740 rtl_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
741 } else if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
742 rtl_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
750 if (find_p2p_ie
== true) {
751 if ((p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) &&
752 (find_p2p_ps_ie
== false))
753 rtl_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
757 static void rtl_p2p_action_ie(struct ieee80211_hw
*hw
, void *data
,
760 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
761 struct ieee80211_mgmt
*mgmt
= (void *)data
;
762 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
763 u8 noa_num
, index
, i
, noa_index
= 0;
766 static u8 p2p_oui_ie_type
[4] = {0x50, 0x6f, 0x9a, 0x09};
768 pos
= (u8
*)&mgmt
->u
.action
.category
;
772 if (pos
[0] == 0x7f) {
773 if (memcmp(&pos
[1], p2p_oui_ie_type
, 4) == 0)
780 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "action frame find P2P IE.\n");
782 while (ie
+ 1 < end
) {
783 noa_len
= READEF2BYTE((__le16
*)&ie
[1]);
784 if (ie
+ 3 + ie
[1] > end
)
788 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "find NOA IE.\n");
789 RT_PRINT_DATA(rtlpriv
, COMP_FW
, DBG_LOUD
, "noa ie ",
791 if ((noa_len
- 2) % 13 != 0) {
792 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
793 "P2P notice of absence: invalid length.%d\n",
797 noa_num
= (noa_len
- 2) / 13;
800 if (rtlpriv
->psc
.p2p_ps_info
.p2p_ps_mode
==
801 P2P_PS_NONE
|| noa_index
!= p2pinfo
->noa_index
) {
802 p2pinfo
->noa_index
= noa_index
;
803 p2pinfo
->opp_ps
= (ie
[4] >> 7);
804 p2pinfo
->ctwindow
= ie
[4] & 0x7F;
805 p2pinfo
->noa_num
= noa_num
;
807 for (i
= 0; i
< noa_num
; i
++) {
808 p2pinfo
->noa_count_type
[i
] =
809 READEF1BYTE(ie
+index
);
811 p2pinfo
->noa_duration
[i
] =
812 READEF4BYTE((__le32
*)ie
+index
);
814 p2pinfo
->noa_interval
[i
] =
815 READEF4BYTE((__le32
*)ie
+index
);
817 p2pinfo
->noa_start_time
[i
] =
818 READEF4BYTE((__le32
*)ie
+index
);
822 if (p2pinfo
->opp_ps
== 1) {
823 p2pinfo
->p2p_ps_mode
= P2P_PS_CTWINDOW
;
824 /* Driver should wait LPS entering
827 if (rtlpriv
->psc
.fw_current_inpsmode
)
830 } else if (p2pinfo
->noa_num
> 0) {
831 p2pinfo
->p2p_ps_mode
= P2P_PS_NOA
;
832 rtl_p2p_ps_cmd(hw
, P2P_PS_ENABLE
);
833 } else if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
834 rtl_p2p_ps_cmd(hw
, P2P_PS_DISABLE
);
843 void rtl_p2p_ps_cmd(struct ieee80211_hw
*hw
, u8 p2p_ps_state
)
845 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
846 struct rtl_ps_ctl
*rtlps
= rtl_psc(rtl_priv(hw
));
847 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlpriv
->psc
.p2p_ps_info
);
849 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, " p2p state %x\n", p2p_ps_state
);
850 switch (p2p_ps_state
) {
852 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
853 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
854 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
855 (u8
*)(&p2p_ps_state
));
857 p2pinfo
->noa_index
= 0;
858 p2pinfo
->ctwindow
= 0;
860 p2pinfo
->noa_num
= 0;
861 p2pinfo
->p2p_ps_mode
= P2P_PS_NONE
;
862 if (rtlps
->fw_current_inpsmode
== true) {
863 if (rtlps
->smart_ps
== 0) {
865 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
866 HW_VAR_H2C_FW_PWRMODE
,
867 (u8
*)(&rtlps
->pwr_mode
));
872 if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
873 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
875 if (p2pinfo
->ctwindow
> 0) {
876 if (rtlps
->smart_ps
!= 0) {
878 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
879 HW_VAR_H2C_FW_PWRMODE
,
880 (u8
*)(&rtlps
->pwr_mode
));
883 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
884 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
885 (u8
*)(&p2p_ps_state
));
889 case P2P_PS_SCAN_DONE
:
890 case P2P_PS_ALLSTASLEEP
:
891 if (p2pinfo
->p2p_ps_mode
> P2P_PS_NONE
) {
892 p2pinfo
->p2p_ps_state
= p2p_ps_state
;
893 rtlpriv
->cfg
->ops
->set_hw_reg(hw
,
894 HW_VAR_H2C_FW_P2P_PS_OFFLOAD
,
895 (u8
*)(&p2p_ps_state
));
901 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
902 "ctwindow %x oppps %x\n", p2pinfo
->ctwindow
, p2pinfo
->opp_ps
);
903 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
904 "count %x duration %x index %x interval %x start time %x noa num %x\n",
905 p2pinfo
->noa_count_type
[0], p2pinfo
->noa_duration
[0],
906 p2pinfo
->noa_index
, p2pinfo
->noa_interval
[0],
907 p2pinfo
->noa_start_time
[0], p2pinfo
->noa_num
);
908 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "end\n");
911 void rtl_p2p_info(struct ieee80211_hw
*hw
, void *data
, unsigned int len
)
913 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
914 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
915 struct ieee80211_hdr
*hdr
= (void *)data
;
919 if (mac
->link_state
!= MAC80211_LINKED
)
921 /* min. beacon length + FCS_LEN */
922 if (len
<= 40 + FCS_LEN
)
925 /* and only beacons from the associated BSSID, please */
926 if (!ether_addr_equal(hdr
->addr3
, rtlpriv
->mac80211
.bssid
))
929 /* check if this really is a beacon */
930 if (!(ieee80211_is_beacon(hdr
->frame_control
) ||
931 ieee80211_is_probe_resp(hdr
->frame_control
) ||
932 ieee80211_is_action(hdr
->frame_control
)))
935 if (ieee80211_is_action(hdr
->frame_control
))
936 rtl_p2p_action_ie(hw
, data
, len
- FCS_LEN
);
938 rtl_p2p_noa_ie(hw
, data
, len
- FCS_LEN
);
940 EXPORT_SYMBOL_GPL(rtl_p2p_info
);