]> Pileus Git - ~andy/linux/blob - drivers/staging/rtl8821ae/ps.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[~andy/linux] / drivers / staging / rtl8821ae / ps.c
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  * 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
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  *****************************************************************************/
29
30 #include "wifi.h"
31 #include "base.h"
32 #include "ps.h"
33 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0))
34 #include <linux/export.h>
35 #endif
36 #include "btcoexist/rtl_btc.h"
37
38 bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
39 {
40         struct rtl_priv *rtlpriv = rtl_priv(hw);
41         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
42         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
43         bool init_status = true;
44
45         /*<1> reset trx ring */
46         if (rtlhal->interface == INTF_PCI)
47                 rtlpriv->intf_ops->reset_trx_ring(hw);
48
49         if (is_hal_stop(rtlhal))
50                 RT_TRACE(COMP_ERR, DBG_WARNING, ("Driver is already down!\n"));
51
52         /*<2> Enable Adapter */
53         rtlpriv->cfg->ops->hw_init(hw);
54         RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
55         /*init_status = false; */
56
57         /*<3> Enable Interrupt */
58         rtlpriv->cfg->ops->enable_interrupt(hw);
59
60         /*<enable timer> */
61         rtl_watch_dog_timer_callback((unsigned long)hw);
62
63         return init_status;
64 }
65 //EXPORT_SYMBOL(rtl_ps_enable_nic);
66
67 bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
68 {
69         bool status = true;
70         struct rtl_priv *rtlpriv = rtl_priv(hw);
71
72         /*<1> Stop all timer */
73         rtl_deinit_deferred_work(hw);
74
75         /*<2> Disable Interrupt */
76         rtlpriv->cfg->ops->disable_interrupt(hw);
77
78         /*<3> Disable Adapter */
79         rtlpriv->cfg->ops->hw_disable(hw);
80
81         return status;
82 }
83 //EXPORT_SYMBOL(rtl_ps_disable_nic);
84
85 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
86                          enum rf_pwrstate state_toset,
87                          u32 changesource, bool protect_or_not)
88 {
89         struct rtl_priv *rtlpriv = rtl_priv(hw);
90         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
91         enum rf_pwrstate rtstate;
92         bool b_actionallowed = false;
93         u16 rfwait_cnt = 0;
94
95         /*protect_or_not = true; */
96
97         if (protect_or_not)
98                 goto no_protect;
99
100         /*
101          *Only one thread can change
102          *the RF state at one time, and others
103          *should wait to be executed.
104          */
105         while (true) {
106                 spin_lock(&rtlpriv->locks.rf_ps_lock);
107                 if (ppsc->rfchange_inprogress) {
108                         spin_unlock(&rtlpriv->locks.rf_ps_lock);
109
110                         RT_TRACE(COMP_ERR, DBG_WARNING,
111                                  ("RF Change in progress!"
112                                   "Wait to set..state_toset(%d).\n",
113                                   state_toset));
114
115                         /* Set RF after the previous action is done.  */
116                         while (ppsc->rfchange_inprogress) {
117                                 rfwait_cnt++;
118                                 mdelay(1);
119                                 /*
120                                  *Wait too long, return false to avoid
121                                  *to be stuck here.
122                                  */
123                                 if (rfwait_cnt > 100)
124                                         return false;
125                         }
126                 } else {
127                         ppsc->rfchange_inprogress = true;
128                         spin_unlock(&rtlpriv->locks.rf_ps_lock);
129                         break;
130                 }
131         }
132
133 no_protect:
134         rtstate = ppsc->rfpwr_state;
135
136         switch (state_toset) {
137         case ERFON:
138                 ppsc->rfoff_reason &= (~changesource);
139
140                 if ((changesource == RF_CHANGE_BY_HW) &&
141                     (ppsc->b_hwradiooff == true)) {
142                         ppsc->b_hwradiooff = false;
143                 }
144
145                 if (!ppsc->rfoff_reason) {
146                         ppsc->rfoff_reason = 0;
147                         b_actionallowed = true;
148                 }
149
150                 break;
151
152         case ERFOFF:
153
154                 if ((changesource == RF_CHANGE_BY_HW) &&
155                     (ppsc->b_hwradiooff == false)) {
156                         ppsc->b_hwradiooff = true;
157                 }
158
159                 ppsc->rfoff_reason |= changesource;
160                 b_actionallowed = true;
161                 break;
162
163         case ERFSLEEP:
164                 ppsc->rfoff_reason |= changesource;
165                 b_actionallowed = true;
166                 break;
167
168         default:
169                 RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not process \n"));
170                 break;
171         }
172
173         if (b_actionallowed)
174                 rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
175
176         if (!protect_or_not) {
177                 spin_lock(&rtlpriv->locks.rf_ps_lock);
178                 ppsc->rfchange_inprogress = false;
179                 spin_unlock(&rtlpriv->locks.rf_ps_lock);
180         }
181
182         return b_actionallowed;
183 }
184 //EXPORT_SYMBOL(rtl_ps_set_rf_state);
185
186 static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
187 {
188         struct rtl_priv *rtlpriv = rtl_priv(hw);
189         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
190         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
191
192         ppsc->b_swrf_processing = true;
193
194         if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
195                 if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
196                     RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
197                     rtlhal->interface == INTF_PCI) {
198                         rtlpriv->intf_ops->disable_aspm(hw);
199                         RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
200                 }
201         }
202
203         if (rtlpriv->cfg->ops->get_btc_status()){
204                 rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
205                                                 ppsc->inactive_pwrstate);
206         }
207         rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
208                             RF_CHANGE_BY_IPS, false);
209
210         if (ppsc->inactive_pwrstate == ERFOFF &&
211             rtlhal->interface == INTF_PCI) {
212                 if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
213                     !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
214                         rtlpriv->intf_ops->enable_aspm(hw);
215                         RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
216                 }
217         }
218
219         ppsc->b_swrf_processing = false;
220 }
221
222 void rtl_ips_nic_off_wq_callback(void *data)
223 {
224         struct rtl_works *rtlworks =
225             container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
226         struct ieee80211_hw *hw = rtlworks->hw;
227         struct rtl_priv *rtlpriv = rtl_priv(hw);
228         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
229         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
230         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
231         enum rf_pwrstate rtstate;
232
233         if (mac->opmode != NL80211_IFTYPE_STATION) {
234                 RT_TRACE(COMP_ERR, DBG_WARNING, ("not station return\n"));
235                 return;
236         }
237
238         if (mac->p2p_in_use)
239                 return;
240
241         if (mac->link_state > MAC80211_NOLINK)
242                 return;
243
244         if (is_hal_stop(rtlhal))
245                 return;
246
247         if (rtlpriv->sec.being_setkey)
248                 return;
249
250         if(rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps)
251                 rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps(hw);
252
253         if (ppsc->b_inactiveps) {
254                 rtstate = ppsc->rfpwr_state;
255
256                 /*
257                  *Do not enter IPS in the following conditions:
258                  *(1) RF is already OFF or Sleep
259                  *(2) b_swrf_processing (indicates the IPS is still under going)
260                  *(3) Connectted (only disconnected can trigger IPS)
261                  *(4) IBSS (send Beacon)
262                  *(5) AP mode (send Beacon)
263                  *(6) monitor mode (rcv packet)
264                  */
265
266                 if (rtstate == ERFON &&
267                     !ppsc->b_swrf_processing &&
268                     (mac->link_state == MAC80211_NOLINK) &&
269                     !mac->act_scanning) {
270                         RT_TRACE(COMP_RF, DBG_LOUD,
271                                  ("IPSEnter(): Turn off RF.\n"));
272
273                         ppsc->inactive_pwrstate = ERFOFF;
274                         ppsc->b_in_powersavemode = true;
275
276                         /*rtl_pci_reset_trx_ring(hw); */
277                         _rtl_ps_inactive_ps(hw);
278                 }
279         }
280 }
281
282 void rtl_ips_nic_off(struct ieee80211_hw *hw)
283 {
284         struct rtl_priv *rtlpriv = rtl_priv(hw);
285
286         /*
287          *because when link with ap, mac80211 will ask us
288          *to disable nic quickly after scan before linking,
289          *this will cause link failed, so we delay 100ms here
290          */
291         queue_delayed_work(rtlpriv->works.rtl_wq,
292                            &rtlpriv->works.ips_nic_off_wq, MSECS(100));
293 }
294
295 /* NOTICE: any opmode should exc nic_on, or disable without
296  * nic_on may something wrong, like adhoc TP*/
297 void rtl_ips_nic_on(struct ieee80211_hw *hw)
298 {
299         struct rtl_priv *rtlpriv = rtl_priv(hw);
300         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
301         enum rf_pwrstate rtstate;
302
303         cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
304
305         spin_lock(&rtlpriv->locks.ips_lock);
306         if (ppsc->b_inactiveps) {
307                 rtstate = ppsc->rfpwr_state;
308
309                 if (rtstate != ERFON &&
310                     !ppsc->b_swrf_processing &&
311                     ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
312
313                         ppsc->inactive_pwrstate = ERFON;
314                         ppsc->b_in_powersavemode = false;
315                         _rtl_ps_inactive_ps(hw);
316                 }
317         }
318         spin_unlock(&rtlpriv->locks.ips_lock);
319 }
320
321 /*for FW LPS*/
322
323 /*
324  *Determine if we can set Fw into PS mode
325  *in current condition.Return true if it
326  *can enter PS mode.
327  */
328 static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
329 {
330         struct rtl_priv *rtlpriv = rtl_priv(hw);
331         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
332         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
333         u32 ps_timediff;
334
335         ps_timediff = jiffies_to_msecs(jiffies -
336                                        ppsc->last_delaylps_stamp_jiffies);
337
338         if (ps_timediff < 2000) {
339                 RT_TRACE(COMP_POWER, DBG_LOUD,
340                          ("Delay enter Fw LPS for DHCP, ARP,"
341                           " or EAPOL exchanging state.\n"));
342                 return false;
343         }
344
345         if (mac->link_state != MAC80211_LINKED)
346                 return false;
347
348         if (mac->opmode == NL80211_IFTYPE_ADHOC)
349                 return false;
350
351         return true;
352 }
353
354 /* Change current and default preamble mode.*/
355 void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
356 {
357         struct rtl_priv *rtlpriv = rtl_priv(hw);
358         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
359         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
360         bool enter_fwlps;
361
362         if (mac->opmode == NL80211_IFTYPE_ADHOC)
363                 return;
364
365         if (mac->link_state != MAC80211_LINKED)
366                 return;
367
368         if (ppsc->dot11_psmode == rt_psmode)
369                 return;
370
371         /* Update power save mode configured. */
372         ppsc->dot11_psmode = rt_psmode;
373
374         /*
375          *<FW control LPS>
376          *1. Enter PS mode
377          *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
378          *   cmd to set Fw into PS mode.
379          *2. Leave PS mode
380          *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active
381          *   mode and set RPWM to turn RF on.
382          */
383
384         if ((ppsc->b_fwctrl_lps) && ppsc->report_linked) {
385                 if (ppsc->dot11_psmode == EACTIVE) {
386                         RT_TRACE(COMP_RF, DBG_DMESG,
387                                  ("FW LPS leave ps_mode:%x\n",
388                                   FW_PS_ACTIVE_MODE));
389                         enter_fwlps = false;
390                         ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
391                         ppsc->smart_ps = 0;
392                         rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION,
393                                                       (u8 *)(&enter_fwlps));
394                         if (ppsc->p2p_ps_info.opp_ps)
395                                 rtl_p2p_ps_cmd(hw,P2P_PS_ENABLE);
396
397                 } else {
398                         if (rtl_get_fwlps_doze(hw)) {
399                                 RT_TRACE(COMP_RF, DBG_DMESG,
400                                          ("FW LPS enter ps_mode:%x\n",
401                                          ppsc->fwctrl_psmode));
402                                 enter_fwlps = true;
403                                 ppsc->pwr_mode = ppsc->fwctrl_psmode;
404                                 ppsc->smart_ps = 2;
405                                 rtlpriv->cfg->ops->set_hw_reg(hw,
406                                                         HW_VAR_FW_LPS_ACTION,
407                                                         (u8 *)(&enter_fwlps));
408
409                         } else {
410                                 /* Reset the power save related parameters. */
411                                 ppsc->dot11_psmode = EACTIVE;
412                         }
413                 }
414         }
415 }
416
417 /*Enter the leisure power save mode.*/
418 void rtl_lps_enter(struct ieee80211_hw *hw)
419 {
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);
423         unsigned long flag;
424
425         if (!ppsc->b_fwctrl_lps)
426                 return;
427
428         if (rtlpriv->sec.being_setkey)
429                 return;
430
431         if (rtlpriv->link_info.b_busytraffic)
432                 return;
433
434         /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
435         if (mac->cnt_after_linked < 5)
436                 return;
437
438         if (mac->opmode == NL80211_IFTYPE_ADHOC)
439                 return;
440
441         if (mac->link_state != MAC80211_LINKED)
442                 return;
443
444         spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
445
446         /* Idle for a while if we connect to AP a while ago. */
447         if (mac->cnt_after_linked >= 2) {
448                 if (ppsc->dot11_psmode == EACTIVE) {
449                         RT_TRACE(COMP_POWER, DBG_LOUD,
450                                  ("Enter 802.11 power save mode...\n"));
451
452                         rtl_lps_set_psmode(hw, EAUTOPS);
453                 }
454         }
455
456         spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
457 }
458
459 /*Leave the leisure power save mode.*/
460 void rtl_lps_leave(struct ieee80211_hw *hw)
461 {
462         struct rtl_priv *rtlpriv = rtl_priv(hw);
463         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
464         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
465         unsigned long flag;
466
467         spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
468
469         if (ppsc->b_fwctrl_lps) {
470                 if (ppsc->dot11_psmode != EACTIVE) {
471
472                         /*FIX ME */
473                         rtlpriv->cfg->ops->enable_interrupt(hw);
474
475                         if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
476                             RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
477                             rtlhal->interface == INTF_PCI) {
478                                 rtlpriv->intf_ops->disable_aspm(hw);
479                                 RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
480                         }
481
482                         RT_TRACE(COMP_POWER, DBG_LOUD,
483                                  ("Busy Traffic,Leave 802.11 power save..\n"));
484
485                         rtl_lps_set_psmode(hw, EACTIVE);
486                 }
487         }
488         spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
489 }
490
491 /* For sw LPS*/
492 void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
493 {
494         struct rtl_priv *rtlpriv = rtl_priv(hw);
495         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
496         struct ieee80211_hdr *hdr = (void *) data;
497         struct ieee80211_tim_ie *tim_ie;
498         u8 *tim;
499         u8 tim_len;
500         bool u_buffed;
501         bool m_buffed;
502
503         if (mac->opmode != NL80211_IFTYPE_STATION)
504                 return;
505
506         if (!rtlpriv->psc.b_swctrl_lps)
507                 return;
508
509         if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
510                 return;
511
512         if (!rtlpriv->psc.sw_ps_enabled)
513                 return;
514
515         if (rtlpriv->psc.b_fwctrl_lps)
516                 return;
517
518         if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
519                 return;
520
521         /* check if this really is a beacon */
522         if (!ieee80211_is_beacon(hdr->frame_control))
523                 return;
524
525         /* min. beacon length + FCS_LEN */
526         if (len <= 40 + FCS_LEN)
527                 return;
528
529         /* and only beacons from the associated BSSID, please */
530         if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
531                 return;
532
533         rtlpriv->psc.last_beacon = jiffies;
534
535         tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
536         if (!tim)
537                 return;
538
539         if (tim[1] < sizeof(*tim_ie))
540                 return;
541
542         tim_len = tim[1];
543         tim_ie = (struct ieee80211_tim_ie *) &tim[2];
544
545 /*<delete in kernel start>*/
546 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
547 /*<delete in kernel end>*/
548         if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
549                 rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
550 /*<delete in kernel start>*/
551 #else
552         if (!WARN_ON_ONCE(!mac->vif->bss_conf.dtim_period))
553                 rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
554 #endif
555 /*<delete in kernel end>*/
556
557         /* Check whenever the PHY can be turned off again. */
558
559         /* 1. What about buffered unicast traffic for our AID? */
560         u_buffed = ieee80211_check_tim(tim_ie, tim_len,
561                                        rtlpriv->mac80211.assoc_id);
562
563         /* 2. Maybe the AP wants to send multicast/broadcast data? */
564         m_buffed = tim_ie->bitmap_ctrl & 0x01;
565         rtlpriv->psc.multi_buffered = m_buffed;
566
567         /* unicast will process by mac80211 through
568          * set ~IEEE80211_CONF_PS, So we just check
569          * multicast frames here */
570         if (!m_buffed ) {//&&) {// !rtlpriv->psc.tx_doing) {
571                 /* back to low-power land. and delay is
572                  * prevent null power save frame tx fail */
573                 queue_delayed_work(rtlpriv->works.rtl_wq,
574                                    &rtlpriv->works.ps_work, MSECS(5));
575         } else {
576                 RT_TRACE(COMP_POWER, DBG_DMESG,
577                          ("u_bufferd: %x, m_buffered: %x\n",
578                           u_buffed, m_buffed));
579         }
580 }
581
582 void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
583 {
584         struct rtl_priv *rtlpriv = rtl_priv(hw);
585         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
586         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
587         unsigned long flag;
588
589         if (!rtlpriv->psc.b_swctrl_lps)
590                 return;
591         if (mac->link_state != MAC80211_LINKED)
592                 return;
593
594         if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
595             RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
596                 rtlpriv->intf_ops->disable_aspm(hw);
597                 RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
598         }
599
600         spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
601         rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
602         spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
603 }
604
605 void rtl_swlps_rfon_wq_callback(void *data)
606 {
607         struct rtl_works *rtlworks =
608             container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
609         struct ieee80211_hw *hw = rtlworks->hw;
610
611         rtl_swlps_rf_awake(hw);
612 }
613
614 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
615 {
616         struct rtl_priv *rtlpriv = rtl_priv(hw);
617         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
618         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
619         unsigned long flag;
620         u8 sleep_intv;
621
622         if (!rtlpriv->psc.sw_ps_enabled)
623                 return;
624
625         if ((rtlpriv->sec.being_setkey) ||
626             (mac->opmode == NL80211_IFTYPE_ADHOC))
627                 return;
628
629         /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
630         if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
631                 return;
632
633         if (rtlpriv->link_info.b_busytraffic)
634                 return;
635
636         spin_lock(&rtlpriv->locks.rf_ps_lock);
637         if (rtlpriv->psc.rfchange_inprogress) {
638                 spin_unlock(&rtlpriv->locks.rf_ps_lock);
639                 return;
640         }
641         spin_unlock(&rtlpriv->locks.rf_ps_lock);
642
643         spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
644         rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS,false);
645         spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
646
647         if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
648             !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
649                 rtlpriv->intf_ops->enable_aspm(hw);
650                 RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
651         }
652
653         /* here is power save alg, when this beacon is DTIM
654          * we will set sleep time to dtim_period * n;
655          * when this beacon is not DTIM, we will set sleep
656          * time to sleep_intv = rtlpriv->psc.dtim_counter or
657          * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
658
659 /*<delete in kernel start>*/
660 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
661 /*<delete in kernel end>*/
662         if (rtlpriv->psc.dtim_counter == 0) {
663                 if (hw->conf.ps_dtim_period == 1)
664                         sleep_intv = hw->conf.ps_dtim_period * 2;
665                 else
666                         sleep_intv = hw->conf.ps_dtim_period;
667         } else {
668                 sleep_intv = rtlpriv->psc.dtim_counter;
669         }
670 /*<delete in kernel start>*/
671 #else
672         if (rtlpriv->psc.dtim_counter == 0) {
673                 if (mac->vif->bss_conf.dtim_period == 1)
674                         sleep_intv = mac->vif->bss_conf.dtim_period * 2;
675                 else
676                         sleep_intv = mac->vif->bss_conf.dtim_period;
677         } else {
678                 sleep_intv = rtlpriv->psc.dtim_counter;
679         }
680 #endif
681 /*<delete in kernel end>*/
682
683         if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
684                 sleep_intv = MAX_SW_LPS_SLEEP_INTV;
685
686         /* this print should always be dtim_conter = 0 &
687          * sleep  = dtim_period, that meaons, we should
688          * awake before every dtim */
689         RT_TRACE(COMP_POWER, DBG_DMESG,
690                  ("dtim_counter:%x will sleep :%d beacon_intv\n",
691                   rtlpriv->psc.dtim_counter, sleep_intv));
692
693         /* we tested that 40ms is enough for sw & hw sw delay */
694         queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
695                         MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
696 }
697
698
699 void rtl_swlps_wq_callback(void *data)
700 {
701         struct rtl_works *rtlworks =
702                 container_of_dwork_rtl(data, struct rtl_works, ps_work);
703         struct ieee80211_hw *hw = rtlworks->hw;
704         struct rtl_priv *rtlpriv = rtl_priv(hw);
705         bool ps = false;
706
707         ps = (hw->conf.flags & IEEE80211_CONF_PS);
708
709         /* we can sleep after ps null send ok */
710         if (rtlpriv->psc.state_inap) {
711                 rtl_swlps_rf_sleep(hw);
712
713                 if (rtlpriv->psc.state && !ps) {
714                         rtlpriv->psc.sleep_ms =
715                                 jiffies_to_msecs(jiffies -
716                                                  rtlpriv->psc.last_action);
717                 }
718
719                 if (ps)
720                         rtlpriv->psc.last_slept = jiffies;
721
722                 rtlpriv->psc.last_action = jiffies;
723                 rtlpriv->psc.state = ps;
724         }
725 }
726
727
728 void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, unsigned int len)
729 {
730         struct rtl_priv *rtlpriv = rtl_priv(hw);
731         struct ieee80211_mgmt *mgmt = (void *)data;
732         struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
733         u8 *pos, *end, *ie;
734         u16 noa_len;
735         static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
736         u8 noa_num, index,i, noa_index = 0;
737         bool find_p2p_ie = false , find_p2p_ps_ie = false;
738         pos = (u8 *)mgmt->u.beacon.variable;
739         end = data + len;
740         ie = NULL;
741
742         while (pos + 1 < end) {
743
744                 if (pos + 2 + pos[1] > end)
745                         return;
746
747                 if (pos[0] == 221 && pos[1] > 4) {
748                         if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
749                                 ie = pos + 2+4;
750                                 break;
751                         }
752                 }
753                 pos += 2 + pos[1];
754         }
755
756         if (ie == NULL)
757                 return;
758         find_p2p_ie = true;
759         /*to find noa ie*/
760         while (ie + 1 < end) {
761                 noa_len = READEF2BYTE(&ie[1]);
762                 if (ie + 3 + ie[1] > end)
763                         return;
764
765                 if (ie[0] == 12) {
766                         find_p2p_ps_ie = true;
767                         if ( (noa_len - 2) % 13 != 0){
768                                 RT_TRACE(COMP_INIT, DBG_LOUD,
769                                          ("P2P notice of absence: "
770                                           "invalid length.%d\n",noa_len));
771                                 return;
772                         } else {
773                                 noa_num = (noa_len - 2) / 13;
774                         }
775                         noa_index = ie[3];
776                         if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == P2P_PS_NONE
777                             || noa_index != p2pinfo->noa_index) {
778                                 RT_TRACE(COMP_FW, DBG_LOUD,
779                                          ("update NOA ie.\n"));
780                                 p2pinfo->noa_index = noa_index;
781                                 p2pinfo->opp_ps= (ie[4] >> 7);
782                                 p2pinfo->ctwindow = ie[4] & 0x7F;
783                                 p2pinfo->noa_num = noa_num;
784                                 index = 5;
785                                 for (i = 0; i< noa_num; i++){
786                                         p2pinfo->noa_count_type[i] =
787                                                         READEF1BYTE(ie+index);
788                                         index += 1;
789                                         p2pinfo->noa_duration[i] =
790                                                         READEF4BYTE(ie+index);
791                                         index += 4;
792                                         p2pinfo->noa_interval[i] =
793                                                         READEF4BYTE(ie+index);
794                                         index += 4;
795                                         p2pinfo->noa_start_time[i] =
796                                                         READEF4BYTE(ie+index);
797                                         index += 4;
798                                 }
799
800                                 if (p2pinfo->opp_ps == 1) {
801                                         p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
802                                         /* Driver should wait LPS
803                                          * entering CTWindow*/
804                                         if (rtlpriv->psc.b_fw_current_inpsmode){
805                                                 rtl_p2p_ps_cmd(hw,
806                                                                P2P_PS_ENABLE);
807                                         }
808                                 } else if (p2pinfo->noa_num > 0) {
809                                         p2pinfo->p2p_ps_mode = P2P_PS_NOA;
810                                         rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
811                                 } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
812                                         rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
813                                 }
814                         }
815
816                 break;
817                 }
818                 ie += 3 + noa_len;
819         }
820
821         if (find_p2p_ie == true) {
822                 if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
823                     (find_p2p_ps_ie == false))
824                         rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
825         }
826 }
827
828 void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, unsigned int len)
829 {
830         struct rtl_priv *rtlpriv = rtl_priv(hw);
831         struct ieee80211_mgmt *mgmt = (void *)data;
832         struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
833         bool find_p2p_ie = false , find_p2p_ps_ie = false;
834         u8 noa_num, index,i, noa_index = 0;
835         u8 *pos, *end, *ie;
836         u16 noa_len;
837         static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
838
839         pos = (u8 *) &mgmt->u.action.category;
840         end = data + len;
841         ie = NULL;
842
843         if (pos[0] == 0x7f ) {
844                 if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0) {
845                         ie = pos + 3+4;
846                 }
847         }
848
849         if (ie == NULL)
850                 return;
851         find_p2p_ie = true;
852
853         RT_TRACE(COMP_FW, DBG_LOUD, ("action frame find P2P IE.\n"));
854         /*to find noa ie*/
855         while (ie + 1 < end) {
856                 noa_len = READEF2BYTE(&ie[1]);
857                 if (ie + 3 + ie[1] > end)
858                         return;
859
860                 if (ie[0] == 12) {
861                         RT_TRACE(COMP_FW, DBG_LOUD, ("find NOA IE.\n"));
862                         RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, ("noa ie "),
863                                       ie, noa_len);
864                         find_p2p_ps_ie = true;
865                         if ( (noa_len - 2) % 13 != 0){
866                                 RT_TRACE(COMP_FW, DBG_LOUD,
867                                          ("P2P notice of absence: "
868                                           "invalid length.%d\n",noa_len));
869                                 return;
870                         } else {
871                                 noa_num = (noa_len - 2) / 13;
872                         }
873                         noa_index = ie[3];
874                         if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == P2P_PS_NONE
875                             || noa_index != p2pinfo->noa_index) {
876                                 p2pinfo->noa_index = noa_index;
877                                 p2pinfo->opp_ps= (ie[4] >> 7);
878                                 p2pinfo->ctwindow = ie[4] & 0x7F;
879                                 p2pinfo->noa_num = noa_num;
880                                 index = 5;
881                                 for (i = 0; i< noa_num; i++){
882                                         p2pinfo->noa_count_type[i] =
883                                                         READEF1BYTE(ie+index);
884                                         index += 1;
885                                         p2pinfo->noa_duration[i] =
886                                                         READEF4BYTE(ie+index);
887                                         index += 4;
888                                         p2pinfo->noa_interval[i] =
889                                                         READEF4BYTE(ie+index);
890                                         index += 4;
891                                         p2pinfo->noa_start_time[i] =
892                                                         READEF4BYTE(ie+index);
893                                         index += 4;
894                                 }
895
896                                 if (p2pinfo->opp_ps == 1) {
897                                         p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
898                                         /* Driver should wait LPS
899                                          * entering CTWindow */
900                                         if (rtlpriv->psc.b_fw_current_inpsmode){
901                                                 rtl_p2p_ps_cmd(hw,
902                                                                P2P_PS_ENABLE);
903                                         }
904                                 } else if (p2pinfo->noa_num > 0) {
905                                         p2pinfo->p2p_ps_mode = P2P_PS_NOA;
906                                         rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
907                                 } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
908                                         rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
909                                 }
910                         }
911
912                 break;
913                 }
914                 ie += 3 + noa_len;
915         }
916
917
918 }
919
920
921 void rtl_p2p_ps_cmd(struct ieee80211_hw *hw,u8 p2p_ps_state)
922 {
923         struct rtl_priv *rtlpriv = rtl_priv(hw);
924         struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
925         struct rtl_p2p_ps_info  *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
926
927         RT_TRACE(COMP_FW, DBG_LOUD, (" p2p state %x\n",p2p_ps_state));
928         switch (p2p_ps_state) {
929                 case P2P_PS_DISABLE:
930                         p2pinfo->p2p_ps_state = p2p_ps_state;
931                         rtlpriv->cfg->ops->set_hw_reg(hw,
932                                                    HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
933                                                    (u8 *)(&p2p_ps_state));
934
935                         p2pinfo->noa_index = 0;
936                         p2pinfo->ctwindow = 0;
937                         p2pinfo->opp_ps = 0;
938                         p2pinfo->noa_num = 0;
939                         p2pinfo->p2p_ps_mode = P2P_PS_NONE;
940                         if (rtlps->b_fw_current_inpsmode == true) {
941                                 if (rtlps->smart_ps == 0) {
942                                         rtlps->smart_ps = 2;
943                                         rtlpriv->cfg->ops->set_hw_reg(hw,
944                                                     HW_VAR_H2C_FW_PWRMODE,
945                                                     (u8 *)(&rtlps->pwr_mode));
946                                 }
947
948                         }
949                         break;
950                 case P2P_PS_ENABLE:
951                         if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
952                                 p2pinfo->p2p_ps_state = p2p_ps_state;
953
954                                 if (p2pinfo->ctwindow > 0) {
955                                         if (rtlps->smart_ps != 0){
956                                                 rtlps->smart_ps = 0;
957                                                 rtlpriv->cfg->ops->set_hw_reg(
958                                                     hw, HW_VAR_H2C_FW_PWRMODE,
959                                                     (u8 *)(&rtlps->pwr_mode));
960                                         }
961                                 }
962                                 rtlpriv->cfg->ops->set_hw_reg(hw,
963                                                 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
964                                                 (u8 *)(&p2p_ps_state));
965
966                         }
967                         break;
968                 case P2P_PS_SCAN:
969                 case P2P_PS_SCAN_DONE:
970                 case P2P_PS_ALLSTASLEEP:
971                         if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
972                                 p2pinfo->p2p_ps_state = p2p_ps_state;
973                                 rtlpriv->cfg->ops->set_hw_reg(hw,
974                                                 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
975                                                 (u8 *)(&p2p_ps_state));
976                         }
977                         break;
978                 default:
979                         break;
980
981         }
982         RT_TRACE(COMP_FW, DBG_LOUD, (" ctwindow %x oppps %x \n",
983                                      p2pinfo->ctwindow,p2pinfo->opp_ps));
984         RT_TRACE(COMP_FW, DBG_LOUD, ("count %x duration %x index %x interval %x"
985                                      " start time %x noa num %x\n",
986                                      p2pinfo->noa_count_type[0],
987                                      p2pinfo->noa_duration[0],
988                                      p2pinfo->noa_index,
989                                      p2pinfo->noa_interval[0],
990                                      p2pinfo->noa_start_time[0],
991                                      p2pinfo->noa_num));
992         RT_TRACE(COMP_FW, DBG_LOUD, ("end\n"));
993 }
994
995 void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
996 {
997         struct rtl_priv *rtlpriv = rtl_priv(hw);
998         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
999         struct ieee80211_hdr *hdr = (void *) data;
1000
1001         if (!mac->p2p)
1002                 return;
1003         if (mac->link_state != MAC80211_LINKED)
1004                 return;
1005         /* min. beacon length + FCS_LEN */
1006         if (len <= 40 + FCS_LEN)
1007                 return;
1008
1009         /* and only beacons from the associated BSSID, please */
1010         if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
1011                 return;
1012
1013         /* check if this really is a beacon */
1014         if (!(ieee80211_is_beacon(hdr->frame_control) ||
1015               ieee80211_is_probe_resp(hdr->frame_control) ||
1016               ieee80211_is_action(hdr->frame_control)))
1017                 return;
1018
1019         if (ieee80211_is_action(hdr->frame_control)) {
1020                 rtl_p2p_action_ie(hw,data,len - FCS_LEN);
1021         } else {
1022                 rtl_p2p_noa_ie(hw,data,len - FCS_LEN);
1023         }
1024
1025 }