Merge tag 'f2fs-fixes-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[deliverable/linux.git] / drivers / staging / rtl8192ee / ps.c
CommitLineData
78de2c06
LF
1/******************************************************************************
2 *
3 * Copyright(c) 2009-2010 Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
16 *
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
21 *
22 * Larry Finger <Larry.Finger@lwfinger.net>
23 *
24 *****************************************************************************/
25
26#include "wifi.h"
27#include "base.h"
28#include "ps.h"
29#include "btcoexist/rtl_btc.h"
30
31bool stg_rtl_ps_enable_nic(struct ieee80211_hw *hw)
32{
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;
37
38 /*<1> reset trx ring */
39 if (rtlhal->interface == INTF_PCI)
40 rtlpriv->intf_ops->reset_trx_ring(hw);
41
42 if (is_hal_stop(rtlhal))
43 RT_TRACE(COMP_ERR, DBG_WARNING, ("Driver is already down!\n"));
44
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; */
49
50 /*<3> Enable Interrupt */
51 rtlpriv->cfg->ops->enable_interrupt(hw);
52
53 /*<enable timer> */
54 rtl92e_watch_dog_timer_callback((unsigned long)hw);
55
56 return init_status;
57}
58EXPORT_SYMBOL(stg_rtl_ps_enable_nic);
59
60bool stg_rtl_ps_disable_nic(struct ieee80211_hw *hw)
61{
62 bool status = true;
63 struct rtl_priv *rtlpriv = rtl_priv(hw);
64
65 /*<1> Stop all timer */
66 rtl92e_deinit_deferred_work(hw);
67
68 /*<2> Disable Interrupt */
69 rtlpriv->cfg->ops->disable_interrupt(hw);
70
71 /*<3> Disable Adapter */
72 rtlpriv->cfg->ops->hw_disable(hw);
73
74 return status;
75}
76EXPORT_SYMBOL(stg_rtl_ps_disable_nic);
77
78bool stg_rtl_ps_set_rf_state(struct ieee80211_hw *hw,
79 enum rf_pwrstate state_toset,
80 u32 changesource, bool protect_or_not)
81{
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;
86 u16 rfwait_cnt = 0;
87
88 /*protect_or_not = true; */
89
90 if (protect_or_not)
91 goto no_protect;
92
93 /*
94 *Only one thread can change
95 *the RF state at one time, and others
96 *should wait to be executed.
97 */
98 while (true) {
99 spin_lock(&rtlpriv->locks.rf_ps_lock);
100 if (ppsc->rfchange_inprogress) {
101 spin_unlock(&rtlpriv->locks.rf_ps_lock);
102
103 RT_TRACE(COMP_ERR, DBG_WARNING,
104 ("RF Change in progress! Wait to set..state_toset(%d)\n",
105 state_toset));
106
107 /* Set RF after the previous action is done. */
108 while (ppsc->rfchange_inprogress) {
109 rfwait_cnt++;
110 mdelay(1);
111 /*
112 *Wait too long, return false to avoid
113 *to be stuck here.
114 */
115 if (rfwait_cnt > 100)
116 return false;
117 }
118 } else {
119 ppsc->rfchange_inprogress = true;
120 spin_unlock(&rtlpriv->locks.rf_ps_lock);
121 break;
122 }
123 }
124
125no_protect:
126 rtstate = ppsc->rfpwr_state;
127
128 switch (state_toset) {
129 case ERFON:
130 ppsc->rfoff_reason &= (~changesource);
131
132 if ((changesource == RF_CHANGE_BY_HW) &&
133 (ppsc->b_hwradiooff)) {
134 ppsc->b_hwradiooff = false;
135 }
136 if (!ppsc->rfoff_reason) {
137 ppsc->rfoff_reason = 0;
138 b_actionallowed = true;
139 }
140 break;
141 case ERFOFF:
142 if ((changesource == RF_CHANGE_BY_HW) &&
143 (!ppsc->b_hwradiooff)) {
144 ppsc->b_hwradiooff = true;
145 }
146 ppsc->rfoff_reason |= changesource;
147 b_actionallowed = true;
148 break;
149 case ERFSLEEP:
150 ppsc->rfoff_reason |= changesource;
151 b_actionallowed = true;
152 break;
153 default:
154 RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not process\n"));
155 break;
156 }
157
158 if (b_actionallowed)
159 rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
160
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);
165 }
166
167 return b_actionallowed;
168}
169EXPORT_SYMBOL(stg_rtl_ps_set_rf_state);
170
171static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
172{
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));
176
177 ppsc->b_swrf_processing = true;
178
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);
185 }
186 }
187
188 stg_rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
189 RF_CHANGE_BY_IPS, false);
190
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);
197 }
198 }
199
200 ppsc->b_swrf_processing = false;
201}
202
203void rtl92e_ips_nic_off_wq_callback(void *data)
204{
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;
213
214 if (mac->opmode != NL80211_IFTYPE_STATION) {
215 RT_TRACE(COMP_ERR, DBG_WARNING, ("not station return\n"));
216 return;
217 }
218
219 if (mac->p2p_in_use)
220 return;
221
222 if (mac->link_state > MAC80211_NOLINK)
223 return;
224
225 if (is_hal_stop(rtlhal))
226 return;
227
228 if (rtlpriv->sec.being_setkey)
229 return;
230
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);
233
234 if (ppsc->b_inactiveps) {
235 rtstate = ppsc->rfpwr_state;
236
237 /*
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)
245 */
246
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"));
253
254 ppsc->inactive_pwrstate = ERFOFF;
255 ppsc->b_in_powersavemode = true;
256
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);
261
262 /*rtl92e_pci_reset_trx_ring(hw); */
263 _rtl_ps_inactive_ps(hw);
264 }
265 }
266}
267
268void rtl92e_ips_nic_off(struct ieee80211_hw *hw)
269{
270 struct rtl_priv *rtlpriv = rtl_priv(hw);
271
272 /*
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
276 */
277 queue_delayed_work(rtlpriv->works.rtl_wq,
278 &rtlpriv->works.ips_nic_off_wq, MSECS(100));
279}
280
281/* NOTICE: any opmode should exc nic_on, or disable without
282 * nic_on may something wrong, like adhoc TP*/
283void rtl92e_ips_nic_on(struct ieee80211_hw *hw)
284{
285 struct rtl_priv *rtlpriv = rtl_priv(hw);
286 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
287 enum rf_pwrstate rtstate;
288
289 cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
290
291 spin_lock(&rtlpriv->locks.ips_lock);
292 if (ppsc->b_inactiveps) {
293 rtstate = ppsc->rfpwr_state;
294
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);
305 }
306 }
307 spin_unlock(&rtlpriv->locks.ips_lock);
308}
309
310/*for FW LPS*/
311
312/*
313 *Determine if we can set Fw into PS mode
314 *in current condition.Return true if it
315 *can enter PS mode.
316 */
317static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
318{
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));
322 u32 ps_timediff;
323
324 ps_timediff = jiffies_to_msecs(jiffies -
325 ppsc->last_delaylps_stamp_jiffies);
326
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"));
330 return false;
331 }
332
333 if (mac->link_state != MAC80211_LINKED)
334 return false;
335
336 if (mac->opmode == NL80211_IFTYPE_ADHOC)
337 return false;
338
339 return true;
340}
341
342/* Change current and default preamble mode.*/
343void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
344{
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));
348 bool enter_fwlps;
349
350 if (mac->opmode == NL80211_IFTYPE_ADHOC)
351 return;
352
353 if (mac->link_state != MAC80211_LINKED)
354 return;
355
356 if (ppsc->dot11_psmode == rt_psmode)
357 return;
358
359 /* Update power save mode configured. */
360 ppsc->dot11_psmode = rt_psmode;
361
362 /*
363 *<FW control LPS>
364 *1. Enter PS mode
365 * Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
366 * cmd to set Fw into PS mode.
367 *2. Leave PS mode
368 * Send H2C fw_pwrmode cmd to Fw to set Fw into Active
369 * mode and set RPWM to turn RF on.
370 */
371
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",
376 FW_PS_ACTIVE_MODE));
377 enter_fwlps = false;
378 ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
379 ppsc->smart_ps = 0;
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);
384
385 if (rtlpriv->cfg->ops->get_btc_status())
386 rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
387 } else {
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);
394 enter_fwlps = true;
395 ppsc->pwr_mode = ppsc->fwctrl_psmode;
396 ppsc->smart_ps = 2;
397 rtlpriv->cfg->ops->set_hw_reg(hw,
398 HW_VAR_FW_LPS_ACTION,
399 (u8 *)(&enter_fwlps));
400
401 } else {
402 /* Reset the power save related parameters. */
403 ppsc->dot11_psmode = EACTIVE;
404 }
405 }
406 }
407}
408
409/*Enter the leisure power save mode.*/
410void rtl92e_lps_enter(struct ieee80211_hw *hw)
411{
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);
415 unsigned long flag;
416
417 if (!ppsc->b_fwctrl_lps)
418 return;
419
420 if (rtlpriv->sec.being_setkey)
421 return;
422
423 if (rtlpriv->link_info.b_busytraffic)
424 return;
425
426 /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
427 if (mac->cnt_after_linked < 5)
428 return;
429
430 if (mac->opmode == NL80211_IFTYPE_ADHOC)
431 return;
432
433 if (mac->link_state != MAC80211_LINKED)
434 return;
435
436 spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
437
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"));
443
444 rtl_lps_set_psmode(hw, EAUTOPS);
445 }
446 }
447
448 spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
449}
450EXPORT_SYMBOL(rtl92e_lps_enter);
451
452/*Leave the leisure power save mode.*/
453void rtl92e_lps_leave(struct ieee80211_hw *hw)
454{
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));
458 unsigned long flag;
459
460 spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
461
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);
469 }
470
471 RT_TRACE(COMP_POWER, DBG_LOUD,
472 ("Busy Traffic,Leave 802.11 power save..\n"));
473
474 rtl_lps_set_psmode(hw, EACTIVE);
475 }
476 }
477 spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
478}
479EXPORT_SYMBOL(rtl92e_lps_leave);
480
481/* For sw LPS*/
482void rtl92e_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
483{
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;
488 u8 *tim;
489 u8 tim_len;
490 bool u_buffed;
491 bool m_buffed;
492
493 if (mac->opmode != NL80211_IFTYPE_STATION)
494 return;
495
496 if (!rtlpriv->psc.b_swctrl_lps)
497 return;
498
499 if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
500 return;
501
502 if (!rtlpriv->psc.sw_ps_enabled)
503 return;
504
505 if (rtlpriv->psc.b_fwctrl_lps)
506 return;
507
508 if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
509 return;
510
511 /* check if this really is a beacon */
512 if (!ieee80211_is_beacon(hdr->frame_control))
513 return;
514
515 /* min. beacon length + FCS_LEN */
516 if (len <= 40 + FCS_LEN)
517 return;
518
519 /* and only beacons from the associated BSSID, please */
520 if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
521 return;
522
523 rtlpriv->psc.last_beacon = jiffies;
524
525 tim = rtl92e_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
526 if (!tim)
527 return;
528
529 if (tim[1] < sizeof(*tim_ie))
530 return;
531
532 tim_len = tim[1];
533 tim_ie = (struct ieee80211_tim_ie *)&tim[2];
534
535 if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
536 rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
537
538 /* Check whenever the PHY can be turned off again. */
539
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);
543
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;
547
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));
556 } else {
557 RT_TRACE(COMP_POWER, DBG_DMESG,
558 ("u_bufferd: %x, m_buffered: %x\n",
559 u_buffed, m_buffed));
560 }
561}
562
563void rtl92e_swlps_rf_awake(struct ieee80211_hw *hw)
564{
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));
568 unsigned long flag;
569
570 if (!rtlpriv->psc.b_swctrl_lps)
571 return;
572 if (mac->link_state != MAC80211_LINKED)
573 return;
574
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);
579 }
580
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);
584}
585
586void rtl92e_swlps_rfon_wq_callback(void *data)
587{
588 struct rtl_works *rtlworks =
589 container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
590 struct ieee80211_hw *hw = rtlworks->hw;
591
592 rtl92e_swlps_rf_awake(hw);
593}
594
595void rtl92e_swlps_rf_sleep(struct ieee80211_hw *hw)
596{
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));
600 unsigned long flag;
601 u8 sleep_intv;
602
603 if (!rtlpriv->psc.sw_ps_enabled)
604 return;
605
606 if ((rtlpriv->sec.being_setkey) ||
607 (mac->opmode == NL80211_IFTYPE_ADHOC))
608 return;
609
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))
612 return;
613
614 if (rtlpriv->link_info.b_busytraffic)
615 return;
616
617 spin_lock(&rtlpriv->locks.rf_ps_lock);
618 if (rtlpriv->psc.rfchange_inprogress) {
619 spin_unlock(&rtlpriv->locks.rf_ps_lock);
620 return;
621 }
622 spin_unlock(&rtlpriv->locks.rf_ps_lock);
623
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);
627
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);
632 }
633
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) */
639
640 if (rtlpriv->psc.dtim_counter == 0) {
641 if (hw->conf.ps_dtim_period == 1)
642 sleep_intv = hw->conf.ps_dtim_period * 2;
643 else
644 sleep_intv = hw->conf.ps_dtim_period;
645 } else {
646 sleep_intv = rtlpriv->psc.dtim_counter;
647 }
648
649 if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
650 sleep_intv = MAX_SW_LPS_SLEEP_INTV;
651
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));
658
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));
662}
663
664
665void rtl92e_swlps_wq_callback(void *data)
666{
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);
671 bool ps = false;
672
673 ps = (hw->conf.flags & IEEE80211_CONF_PS);
674
675 /* we can sleep after ps null send ok */
676 if (rtlpriv->psc.state_inap) {
677 rtl92e_swlps_rf_sleep(hw);
678
679 if (rtlpriv->psc.state && !ps) {
680 rtlpriv->psc.sleep_ms =
681 jiffies_to_msecs(jiffies -
682 rtlpriv->psc.last_action);
683 }
684
685 if (ps)
686 rtlpriv->psc.last_slept = jiffies;
687
688 rtlpriv->psc.last_action = jiffies;
689 rtlpriv->psc.state = ps;
690 }
691}
692
693static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
694 unsigned int len)
695{
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);
699 u8 *pos, *end, *ie;
700 u16 noa_len;
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;
705 end = data + len;
706 ie = NULL;
707
708 while (pos + 1 < end) {
709 if (pos + 2 + pos[1] > end)
710 return;
711
712 if (pos[0] == 221 && pos[1] > 4) {
713 if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
714 ie = pos + 2+4;
715 break;
716 }
717 }
718 pos += 2 + pos[1];
719 }
720
721 if (ie == NULL)
722 return;
723 find_p2p_ie = true;
724 /*to find noa ie*/
725 while (ie + 1 < end) {
726 noa_len = READEF2BYTE((__le16 *)&ie[1]);
727 if (ie + 3 + ie[1] > end)
728 return;
729
730 if (ie[0] == 12) {
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",
735 noa_len));
736 return;
737 } else {
738 noa_num = (noa_len - 2) / 13;
739 }
740 noa_index = ie[3];
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;
749 index = 5;
750 for (i = 0; i < noa_num; i++) {
751 p2pinfo->noa_count_type[i] =
752 READEF1BYTE(ie+index);
753 index += 1;
754 p2pinfo->noa_duration[i] =
755 READEF4BYTE((__le32 *)ie+index);
756 index += 4;
757 p2pinfo->noa_interval[i] =
758 READEF4BYTE((__le32 *)ie+index);
759 index += 4;
760 p2pinfo->noa_start_time[i] =
761 READEF4BYTE((__le32 *)ie+index);
762 index += 4;
763 }
764
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,
771 P2P_PS_ENABLE);
772 }
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);
778 }
779 }
780
781 break;
782 }
783 ie += 3 + noa_len;
784 }
785
786 if (find_p2p_ie) {
787 if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
788 (!find_p2p_ps_ie))
789 rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
790 }
791}
792
793static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
794 unsigned int len)
795{
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;
801 u8 *pos, *end, *ie;
802 u16 noa_len;
803 static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
804
805 pos = (u8 *)&mgmt->u.action.category;
806 end = data + len;
807 ie = NULL;
808
809 if (pos[0] == 0x7f) {
810 if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
811 ie = pos + 3+4;
812 }
813
814 if (ie == NULL)
815 return;
816 find_p2p_ie = true;
817
818 RT_TRACE(COMP_FW, DBG_LOUD, ("action frame find P2P IE.\n"));
819 /*to find noa ie*/
820 while (ie + 1 < end) {
821 noa_len = READEF2BYTE((__le16 *)&ie[1]);
822 if (ie + 3 + ie[1] > end)
823 return;
824
825 if (ie[0] == 12) {
826 RT_TRACE(COMP_FW, DBG_LOUD, ("find NOA IE\n"));
827 RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
828 ie, noa_len);
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",
833 noa_len));
834 return;
835 } else {
836 noa_num = (noa_len - 2) / 13;
837 }
838 noa_index = ie[3];
839 if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
840 P2P_PS_NONE ||
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;
846 index = 5;
847 for (i = 0; i < noa_num; i++) {
848 p2pinfo->noa_count_type[i] =
849 READEF1BYTE(ie+index);
850 index += 1;
851 p2pinfo->noa_duration[i] =
852 READEF4BYTE((__le32 *)ie+index);
853 index += 4;
854 p2pinfo->noa_interval[i] =
855 READEF4BYTE((__le32 *)ie+index);
856 index += 4;
857 p2pinfo->noa_start_time[i] =
858 READEF4BYTE((__le32 *)ie+index);
859 index += 4;
860 }
861
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,
868 P2P_PS_ENABLE);
869 }
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);
875 }
876 }
877
878 break;
879 }
880 ie += 3 + noa_len;
881 }
882}
883
884void rtl92e_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
885{
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);
889
890 RT_TRACE(COMP_FW, DBG_LOUD, ("p2p state %x\n", p2p_ps_state));
891 switch (p2p_ps_state) {
892 case P2P_PS_DISABLE:
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));
897
898 p2pinfo->noa_index = 0;
899 p2pinfo->ctwindow = 0;
900 p2pinfo->opp_ps = 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) {
905 rtlps->smart_ps = 2;
906 rtlpriv->cfg->ops->set_hw_reg(hw,
907 HW_VAR_H2C_FW_PWRMODE,
908 (u8 *)(&rtlps->pwr_mode));
909 }
910 }
911 break;
912 case P2P_PS_ENABLE:
913 if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
914 p2pinfo->p2p_ps_state = p2p_ps_state;
915
916 if (p2pinfo->ctwindow > 0) {
917 if (rtlps->smart_ps != 0) {
918 rtlps->smart_ps = 0;
919 rtlpriv->cfg->ops->set_hw_reg(
920 hw, HW_VAR_H2C_FW_PWRMODE,
921 (u8 *)(&rtlps->pwr_mode));
922 }
923 }
924 rtlpriv->cfg->ops->set_hw_reg(hw,
925 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
926 (u8 *)(&p2p_ps_state));
927 }
928 break;
929 case P2P_PS_SCAN:
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));
937 }
938 break;
939 default:
940 break;
941 }
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],
948 p2pinfo->noa_index,
949 p2pinfo->noa_interval[0],
950 p2pinfo->noa_start_time[0],
951 p2pinfo->noa_num));
952 RT_TRACE(COMP_FW, DBG_LOUD, ("end\n"));
953}
954
955void rtl92e_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
956{
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;
960
961 if (!mac->p2p)
962 return;
963 if (mac->link_state != MAC80211_LINKED)
964 return;
965 /* min. beacon length + FCS_LEN */
966 if (len <= 40 + FCS_LEN)
967 return;
968
969 /* and only beacons from the associated BSSID, please */
970 if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
971 return;
972
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)))
977 return;
978
979 if (ieee80211_is_action(hdr->frame_control))
980 rtl_p2p_action_ie(hw , data , len - FCS_LEN);
981 else
982 rtl_p2p_noa_ie(hw , data , len - FCS_LEN);
983}
This page took 0.080667 seconds and 5 git commands to generate.