drivers/net: Add export.h to files using EXPORT_SYMBOL/THIS_MODULE
[pandora-kernel.git] / drivers / net / wireless / rtlwifi / 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 <linux/export.h>
31 #include "wifi.h"
32 #include "base.h"
33 #include "ps.h"
34
35 bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
36 {
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));
40
41         /*<1> reset trx ring */
42         if (rtlhal->interface == INTF_PCI)
43                 rtlpriv->intf_ops->reset_trx_ring(hw);
44
45         if (is_hal_stop(rtlhal))
46                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
47                          ("Driver is already down!\n"));
48
49         /*<2> Enable Adapter */
50         rtlpriv->cfg->ops->hw_init(hw);
51         RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
52
53         /*<3> Enable Interrupt */
54         rtlpriv->cfg->ops->enable_interrupt(hw);
55
56         /*<enable timer> */
57         rtl_watch_dog_timer_callback((unsigned long)hw);
58
59         return true;
60 }
61 EXPORT_SYMBOL(rtl_ps_enable_nic);
62
63 bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
64 {
65         struct rtl_priv *rtlpriv = rtl_priv(hw);
66
67         /*<1> Stop all timer */
68         rtl_deinit_deferred_work(hw);
69
70         /*<2> Disable Interrupt */
71         rtlpriv->cfg->ops->disable_interrupt(hw);
72         tasklet_kill(&rtlpriv->works.irq_tasklet);
73
74         /*<3> Disable Adapter */
75         rtlpriv->cfg->ops->hw_disable(hw);
76
77         return true;
78 }
79 EXPORT_SYMBOL(rtl_ps_disable_nic);
80
81 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
82                          enum rf_pwrstate state_toset,
83                          u32 changesource)
84 {
85         struct rtl_priv *rtlpriv = rtl_priv(hw);
86         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
87         bool actionallowed = false;
88
89         switch (state_toset) {
90         case ERFON:
91                 ppsc->rfoff_reason &= (~changesource);
92
93                 if ((changesource == RF_CHANGE_BY_HW) &&
94                     (ppsc->hwradiooff)) {
95                         ppsc->hwradiooff = false;
96                 }
97
98                 if (!ppsc->rfoff_reason) {
99                         ppsc->rfoff_reason = 0;
100                         actionallowed = true;
101                 }
102
103                 break;
104
105         case ERFOFF:
106
107                 if ((changesource == RF_CHANGE_BY_HW)
108                     && (ppsc->hwradiooff == false)) {
109                         ppsc->hwradiooff = true;
110                 }
111
112                 ppsc->rfoff_reason |= changesource;
113                 actionallowed = true;
114                 break;
115
116         case ERFSLEEP:
117                 ppsc->rfoff_reason |= changesource;
118                 actionallowed = true;
119                 break;
120
121         default:
122                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
123                          ("switch case not process\n"));
124                 break;
125         }
126
127         if (actionallowed)
128                 rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
129
130         return actionallowed;
131 }
132 EXPORT_SYMBOL(rtl_ps_set_rf_state);
133
134 static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
135 {
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));
139
140         ppsc->swrf_processing = true;
141
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);
149                 }
150         }
151
152         rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, RF_CHANGE_BY_IPS);
153
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);
160                 }
161         }
162
163         ppsc->swrf_processing = false;
164 }
165
166 void rtl_ips_nic_off_wq_callback(void *data)
167 {
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;
176
177         if (mac->opmode != NL80211_IFTYPE_STATION) {
178                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
179                          ("not station return\n"));
180                 return;
181         }
182
183         if (mac->link_state > MAC80211_NOLINK)
184                 return;
185
186         if (is_hal_stop(rtlhal))
187                 return;
188
189         if (rtlpriv->sec.being_setkey)
190                 return;
191
192         if (ppsc->inactiveps) {
193                 rtstate = ppsc->rfpwr_state;
194
195                 /*
196                  *Do not enter IPS in the following conditions:
197                  *(1) RF is already OFF or Sleep
198                  *(2) swrf_processing (indicates the IPS is still under going)
199                  *(3) Connectted (only disconnected can trigger IPS)
200                  *(4) IBSS (send Beacon)
201                  *(5) AP mode (send Beacon)
202                  *(6) monitor mode (rcv packet)
203                  */
204
205                 if (rtstate == ERFON &&
206                     !ppsc->swrf_processing &&
207                     (mac->link_state == MAC80211_NOLINK) &&
208                     !mac->act_scanning) {
209                         RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
210                                  ("IPSEnter(): Turn off RF.\n"));
211
212                         ppsc->inactive_pwrstate = ERFOFF;
213                         ppsc->in_powersavemode = true;
214
215                         /*rtl_pci_reset_trx_ring(hw); */
216                         _rtl_ps_inactive_ps(hw);
217                 }
218         }
219 }
220
221 void rtl_ips_nic_off(struct ieee80211_hw *hw)
222 {
223         struct rtl_priv *rtlpriv = rtl_priv(hw);
224
225         /*
226          *because when link with ap, mac80211 will ask us
227          *to disable nic quickly after scan before linking,
228          *this will cause link failed, so we delay 100ms here
229          */
230         queue_delayed_work(rtlpriv->works.rtl_wq,
231                            &rtlpriv->works.ips_nic_off_wq, MSECS(100));
232 }
233
234 void rtl_ips_nic_on(struct ieee80211_hw *hw)
235 {
236         struct rtl_priv *rtlpriv = rtl_priv(hw);
237         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
238         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
239         enum rf_pwrstate rtstate;
240
241         if (mac->opmode != NL80211_IFTYPE_STATION)
242                 return;
243
244         spin_lock(&rtlpriv->locks.ips_lock);
245
246         if (ppsc->inactiveps) {
247                 rtstate = ppsc->rfpwr_state;
248
249                 if (rtstate != ERFON &&
250                     !ppsc->swrf_processing &&
251                     ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
252
253                         ppsc->inactive_pwrstate = ERFON;
254                         ppsc->in_powersavemode = false;
255
256                         _rtl_ps_inactive_ps(hw);
257                 }
258         }
259
260         spin_unlock(&rtlpriv->locks.ips_lock);
261 }
262
263 /*for FW LPS*/
264
265 /*
266  *Determine if we can set Fw into PS mode
267  *in current condition.Return TRUE if it
268  *can enter PS mode.
269  */
270 static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
271 {
272         struct rtl_priv *rtlpriv = rtl_priv(hw);
273         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
274         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
275         u32 ps_timediff;
276
277         ps_timediff = jiffies_to_msecs(jiffies -
278                                        ppsc->last_delaylps_stamp_jiffies);
279
280         if (ps_timediff < 2000) {
281                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
282                          ("Delay enter Fw LPS for DHCP, ARP,"
283                           " or EAPOL exchanging state.\n"));
284                 return false;
285         }
286
287         if (mac->link_state != MAC80211_LINKED)
288                 return false;
289
290         if (mac->opmode == NL80211_IFTYPE_ADHOC)
291                 return false;
292
293         return true;
294 }
295
296 /* Change current and default preamble mode.*/
297 static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
298 {
299         struct rtl_priv *rtlpriv = rtl_priv(hw);
300         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
301         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
302         u8 rpwm_val, fw_pwrmode;
303
304         if (mac->opmode == NL80211_IFTYPE_ADHOC)
305                 return;
306
307         if (mac->link_state != MAC80211_LINKED)
308                 return;
309
310         if (ppsc->dot11_psmode == rt_psmode)
311                 return;
312
313         /* Update power save mode configured. */
314         ppsc->dot11_psmode = rt_psmode;
315
316         /*
317          *<FW control LPS>
318          *1. Enter PS mode
319          *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
320          *   cmd to set Fw into PS mode.
321          *2. Leave PS mode
322          *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active
323          *   mode and set RPWM to turn RF on.
324          */
325
326         if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
327                 bool fw_current_inps;
328                 if (ppsc->dot11_psmode == EACTIVE) {
329                         RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
330                                  ("FW LPS leave ps_mode:%x\n",
331                                   FW_PS_ACTIVE_MODE));
332
333                         rpwm_val = 0x0C;        /* RF on */
334                         fw_pwrmode = FW_PS_ACTIVE_MODE;
335                         rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
336                                         (u8 *) (&rpwm_val));
337                         rtlpriv->cfg->ops->set_hw_reg(hw,
338                                         HW_VAR_H2C_FW_PWRMODE,
339                                         (u8 *) (&fw_pwrmode));
340                         fw_current_inps = false;
341
342                         rtlpriv->cfg->ops->set_hw_reg(hw,
343                                         HW_VAR_FW_PSMODE_STATUS,
344                                         (u8 *) (&fw_current_inps));
345
346                 } else {
347                         if (rtl_get_fwlps_doze(hw)) {
348                                 RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
349                                                 ("FW LPS enter ps_mode:%x\n",
350                                                  ppsc->fwctrl_psmode));
351
352                                 rpwm_val = 0x02;        /* RF off */
353                                 fw_current_inps = true;
354                                 rtlpriv->cfg->ops->set_hw_reg(hw,
355                                                 HW_VAR_FW_PSMODE_STATUS,
356                                                 (u8 *) (&fw_current_inps));
357                                 rtlpriv->cfg->ops->set_hw_reg(hw,
358                                                 HW_VAR_H2C_FW_PWRMODE,
359                                                 (u8 *) (&ppsc->fwctrl_psmode));
360
361                                 rtlpriv->cfg->ops->set_hw_reg(hw,
362                                                 HW_VAR_SET_RPWM,
363                                                 (u8 *) (&rpwm_val));
364                         } else {
365                                 /* Reset the power save related parameters. */
366                                 ppsc->dot11_psmode = EACTIVE;
367                         }
368                 }
369         }
370 }
371
372 /*Enter the leisure power save mode.*/
373 void rtl_lps_enter(struct ieee80211_hw *hw)
374 {
375         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
376         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
377         struct rtl_priv *rtlpriv = rtl_priv(hw);
378
379         if (!ppsc->fwctrl_lps)
380                 return;
381
382         if (rtlpriv->sec.being_setkey)
383                 return;
384
385         if (rtlpriv->link_info.busytraffic)
386                 return;
387
388         /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
389         if (mac->cnt_after_linked < 5)
390                 return;
391
392         if (mac->opmode == NL80211_IFTYPE_ADHOC)
393                 return;
394
395         if (mac->link_state != MAC80211_LINKED)
396                 return;
397
398         spin_lock(&rtlpriv->locks.lps_lock);
399
400         /* Idle for a while if we connect to AP a while ago. */
401         if (mac->cnt_after_linked >= 2) {
402                 if (ppsc->dot11_psmode == EACTIVE) {
403                         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
404                                         ("Enter 802.11 power save mode...\n"));
405
406                         rtl_lps_set_psmode(hw, EAUTOPS);
407                 }
408         }
409
410         spin_unlock(&rtlpriv->locks.lps_lock);
411 }
412
413 /*Leave the leisure power save mode.*/
414 void rtl_lps_leave(struct ieee80211_hw *hw)
415 {
416         struct rtl_priv *rtlpriv = rtl_priv(hw);
417         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
418         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
419
420         spin_lock(&rtlpriv->locks.lps_lock);
421
422         if (ppsc->fwctrl_lps) {
423                 if (ppsc->dot11_psmode != EACTIVE) {
424
425                         /*FIX ME */
426                         rtlpriv->cfg->ops->enable_interrupt(hw);
427
428                         if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
429                             RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
430                             rtlhal->interface == INTF_PCI) {
431                                 rtlpriv->intf_ops->disable_aspm(hw);
432                                 RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
433                         }
434
435                         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
436                                  ("Busy Traffic,Leave 802.11 power save..\n"));
437
438                         rtl_lps_set_psmode(hw, EACTIVE);
439                 }
440         }
441         spin_unlock(&rtlpriv->locks.lps_lock);
442 }
443
444 /* For sw LPS*/
445 void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
446 {
447         struct rtl_priv *rtlpriv = rtl_priv(hw);
448         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
449         struct ieee80211_hdr *hdr = (void *) data;
450         struct ieee80211_tim_ie *tim_ie;
451         u8 *tim;
452         u8 tim_len;
453         bool u_buffed;
454         bool m_buffed;
455
456         if (mac->opmode != NL80211_IFTYPE_STATION)
457                 return;
458
459         if (!rtlpriv->psc.swctrl_lps)
460                 return;
461
462         if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
463                 return;
464
465         if (!rtlpriv->psc.sw_ps_enabled)
466                 return;
467
468         if (rtlpriv->psc.fwctrl_lps)
469                 return;
470
471         if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
472                 return;
473
474         /* check if this really is a beacon */
475         if (!ieee80211_is_beacon(hdr->frame_control))
476                 return;
477
478         /* min. beacon length + FCS_LEN */
479         if (len <= 40 + FCS_LEN)
480                 return;
481
482         /* and only beacons from the associated BSSID, please */
483         if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
484                 return;
485
486         rtlpriv->psc.last_beacon = jiffies;
487
488         tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
489         if (!tim)
490                 return;
491
492         if (tim[1] < sizeof(*tim_ie))
493                 return;
494
495         tim_len = tim[1];
496         tim_ie = (struct ieee80211_tim_ie *) &tim[2];
497
498         if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
499                 rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
500
501         /* Check whenever the PHY can be turned off again. */
502
503         /* 1. What about buffered unicast traffic for our AID? */
504         u_buffed = ieee80211_check_tim(tim_ie, tim_len,
505                                        rtlpriv->mac80211.assoc_id);
506
507         /* 2. Maybe the AP wants to send multicast/broadcast data? */
508         m_buffed = tim_ie->bitmap_ctrl & 0x01;
509         rtlpriv->psc.multi_buffered = m_buffed;
510
511         /* unicast will process by mac80211 through
512          * set ~IEEE80211_CONF_PS, So we just check
513          * multicast frames here */
514         if (!m_buffed) {
515                 /* back to low-power land. and delay is
516                  * prevent null power save frame tx fail */
517                 queue_delayed_work(rtlpriv->works.rtl_wq,
518                                 &rtlpriv->works.ps_work, MSECS(5));
519         } else {
520                 RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, "
521                                 "m_buffered: %x\n", u_buffed, m_buffed));
522         }
523 }
524
525 void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
526 {
527         struct rtl_priv *rtlpriv = rtl_priv(hw);
528         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
529         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
530
531         if (!rtlpriv->psc.swctrl_lps)
532                 return;
533         if (mac->link_state != MAC80211_LINKED)
534                 return;
535
536         if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
537                 RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
538                 rtlpriv->intf_ops->disable_aspm(hw);
539                 RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
540         }
541
542         spin_lock(&rtlpriv->locks.lps_lock);
543         rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS);
544         spin_unlock(&rtlpriv->locks.lps_lock);
545 }
546
547 void rtl_swlps_rfon_wq_callback(void *data)
548 {
549         struct rtl_works *rtlworks =
550             container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
551         struct ieee80211_hw *hw = rtlworks->hw;
552
553         rtl_swlps_rf_awake(hw);
554 }
555
556 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
557 {
558         struct rtl_priv *rtlpriv = rtl_priv(hw);
559         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
560         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
561         u8 sleep_intv;
562
563         if (!rtlpriv->psc.sw_ps_enabled)
564                 return;
565
566         if ((rtlpriv->sec.being_setkey) ||
567             (mac->opmode == NL80211_IFTYPE_ADHOC))
568                 return;
569
570         /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
571         if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
572                 return;
573
574         if (rtlpriv->link_info.busytraffic)
575                 return;
576
577         spin_lock(&rtlpriv->locks.lps_lock);
578         rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS);
579         spin_unlock(&rtlpriv->locks.lps_lock);
580
581         if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
582                 !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
583                 rtlpriv->intf_ops->enable_aspm(hw);
584                 RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
585         }
586
587         /* here is power save alg, when this beacon is DTIM
588          * we will set sleep time to dtim_period * n;
589          * when this beacon is not DTIM, we will set sleep
590          * time to sleep_intv = rtlpriv->psc.dtim_counter or
591          * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
592
593         if (rtlpriv->psc.dtim_counter == 0) {
594                 if (hw->conf.ps_dtim_period == 1)
595                         sleep_intv = hw->conf.ps_dtim_period * 2;
596                 else
597                         sleep_intv = hw->conf.ps_dtim_period;
598         } else {
599                 sleep_intv = rtlpriv->psc.dtim_counter;
600         }
601
602         if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
603                 sleep_intv = MAX_SW_LPS_SLEEP_INTV;
604
605         /* this print should always be dtim_conter = 0 &
606          * sleep  = dtim_period, that meaons, we should
607          * awake before every dtim */
608         RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
609                  ("dtim_counter:%x will sleep :%d"
610                  " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv));
611
612         /* we tested that 40ms is enough for sw & hw sw delay */
613         queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
614                         MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
615 }
616
617
618 void rtl_swlps_wq_callback(void *data)
619 {
620         struct rtl_works *rtlworks = container_of_dwork_rtl(data,
621                                      struct rtl_works,
622                                      ps_work);
623         struct ieee80211_hw *hw = rtlworks->hw;
624         struct rtl_priv *rtlpriv = rtl_priv(hw);
625         bool ps = false;
626
627         ps = (hw->conf.flags & IEEE80211_CONF_PS);
628
629         /* we can sleep after ps null send ok */
630         if (rtlpriv->psc.state_inap) {
631                 rtl_swlps_rf_sleep(hw);
632
633                 if (rtlpriv->psc.state && !ps) {
634                         rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies -
635                                         rtlpriv->psc.last_action);
636                 }
637
638                 if (ps)
639                         rtlpriv->psc.last_slept = jiffies;
640
641                 rtlpriv->psc.last_action = jiffies;
642                 rtlpriv->psc.state = ps;
643         }
644 }