Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[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 "wifi.h"
31 #include "base.h"
32 #include "ps.h"
33
34 bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
35 {
36         struct rtl_priv *rtlpriv = rtl_priv(hw);
37         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
38         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
39         bool init_status = true;
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         /*init_status = false; */
53
54         /*<3> Enable Interrupt */
55         rtlpriv->cfg->ops->enable_interrupt(hw);
56
57         /*<enable timer> */
58         rtl_watch_dog_timer_callback((unsigned long)hw);
59
60         return init_status;
61 }
62 EXPORT_SYMBOL(rtl_ps_enable_nic);
63
64 bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
65 {
66         bool status = true;
67         struct rtl_priv *rtlpriv = rtl_priv(hw);
68
69         /*<1> Stop all timer */
70         rtl_deinit_deferred_work(hw);
71
72         /*<2> Disable Interrupt */
73         rtlpriv->cfg->ops->disable_interrupt(hw);
74
75         /*<3> Disable Adapter */
76         rtlpriv->cfg->ops->hw_disable(hw);
77
78         return status;
79 }
80 EXPORT_SYMBOL(rtl_ps_disable_nic);
81
82 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
83                          enum rf_pwrstate state_toset,
84                          u32 changesource, bool protect_or_not)
85 {
86         struct rtl_priv *rtlpriv = rtl_priv(hw);
87         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
88         enum rf_pwrstate rtstate;
89         bool b_actionallowed = false;
90         u16 rfwait_cnt = 0;
91         unsigned long flag;
92
93         /*protect_or_not = true; */
94
95         if (protect_or_not)
96                 goto no_protect;
97
98         /*
99          *Only one thread can change
100          *the RF state at one time, and others
101          *should wait to be executed.
102          */
103         while (true) {
104                 spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
105                 if (ppsc->rfchange_inprogress) {
106                         spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock,
107                                                flag);
108
109                         RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
110                                  ("RF Change in progress!"
111                                   "Wait to set..state_toset(%d).\n",
112                                   state_toset));
113
114                         /* Set RF after the previous action is done.  */
115                         while (ppsc->rfchange_inprogress) {
116                                 rfwait_cnt++;
117                                 mdelay(1);
118
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_irqrestore(&rtlpriv->locks.rf_ps_lock,
129                                                flag);
130                         break;
131                 }
132         }
133
134 no_protect:
135         rtstate = ppsc->rfpwr_state;
136
137         switch (state_toset) {
138         case ERFON:
139                 ppsc->rfoff_reason &= (~changesource);
140
141                 if ((changesource == RF_CHANGE_BY_HW) &&
142                     (ppsc->b_hwradiooff == true)) {
143                         ppsc->b_hwradiooff = false;
144                 }
145
146                 if (!ppsc->rfoff_reason) {
147                         ppsc->rfoff_reason = 0;
148                         b_actionallowed = true;
149                 }
150
151                 break;
152
153         case ERFOFF:
154
155                 if ((changesource == RF_CHANGE_BY_HW)
156                     && (ppsc->b_hwradiooff == false)) {
157                         ppsc->b_hwradiooff = true;
158                 }
159
160                 ppsc->rfoff_reason |= changesource;
161                 b_actionallowed = true;
162                 break;
163
164         case ERFSLEEP:
165                 ppsc->rfoff_reason |= changesource;
166                 b_actionallowed = true;
167                 break;
168
169         default:
170                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
171                          ("switch case not process\n"));
172                 break;
173         }
174
175         if (b_actionallowed)
176                 rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
177
178         if (!protect_or_not) {
179                 spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
180                 ppsc->rfchange_inprogress = false;
181                 spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
182         }
183
184         return b_actionallowed;
185 }
186 EXPORT_SYMBOL(rtl_ps_set_rf_state);
187
188 static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
189 {
190         struct rtl_priv *rtlpriv = rtl_priv(hw);
191         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
192         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
193
194         ppsc->b_swrf_processing = true;
195
196         if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
197                 if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
198                     RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) &&
199                     rtlhal->interface == INTF_PCI) {
200                         rtlpriv->intf_ops->disable_aspm(hw);
201                         RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
202                 }
203         }
204
205         rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
206                             RF_CHANGE_BY_IPS, false);
207
208         if (ppsc->inactive_pwrstate == ERFOFF &&
209             rtlhal->interface == INTF_PCI) {
210                 if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
211                         rtlpriv->intf_ops->enable_aspm(hw);
212                         RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
213                 }
214         }
215
216         ppsc->b_swrf_processing = false;
217 }
218
219 void rtl_ips_nic_off_wq_callback(void *data)
220 {
221         struct rtl_works *rtlworks =
222             container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
223         struct ieee80211_hw *hw = rtlworks->hw;
224         struct rtl_priv *rtlpriv = rtl_priv(hw);
225         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
226         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
227         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
228         enum rf_pwrstate rtstate;
229
230         if (mac->opmode != NL80211_IFTYPE_STATION) {
231                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
232                          ("not station return\n"));
233                 return;
234         }
235
236         if (is_hal_stop(rtlhal))
237                 return;
238
239         if (rtlpriv->sec.being_setkey)
240                 return;
241
242         if (ppsc->b_inactiveps) {
243                 rtstate = ppsc->rfpwr_state;
244
245                 /*
246                  *Do not enter IPS in the following conditions:
247                  *(1) RF is already OFF or Sleep
248                  *(2) b_swrf_processing (indicates the IPS is still under going)
249                  *(3) Connectted (only disconnected can trigger IPS)
250                  *(4) IBSS (send Beacon)
251                  *(5) AP mode (send Beacon)
252                  *(6) monitor mode (rcv packet)
253                  */
254
255                 if (rtstate == ERFON &&
256                     !ppsc->b_swrf_processing &&
257                     (mac->link_state == MAC80211_NOLINK) &&
258                     !mac->act_scanning) {
259                         RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
260                                  ("IPSEnter(): Turn off RF.\n"));
261
262                         ppsc->inactive_pwrstate = ERFOFF;
263                         ppsc->b_in_powersavemode = true;
264
265                         /*rtl_pci_reset_trx_ring(hw); */
266                         _rtl_ps_inactive_ps(hw);
267                 }
268         }
269 }
270
271 void rtl_ips_nic_off(struct ieee80211_hw *hw)
272 {
273         struct rtl_priv *rtlpriv = rtl_priv(hw);
274
275         /*
276          *because when link with ap, mac80211 will ask us
277          *to disable nic quickly after scan before linking,
278          *this will cause link failed, so we delay 100ms here
279          */
280         queue_delayed_work(rtlpriv->works.rtl_wq,
281                            &rtlpriv->works.ips_nic_off_wq, MSECS(100));
282 }
283
284 void rtl_ips_nic_on(struct ieee80211_hw *hw)
285 {
286         struct rtl_priv *rtlpriv = rtl_priv(hw);
287         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
288         enum rf_pwrstate rtstate;
289         unsigned long flags;
290
291         spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
292
293         if (ppsc->b_inactiveps) {
294                 rtstate = ppsc->rfpwr_state;
295
296                 if (rtstate != ERFON &&
297                     !ppsc->b_swrf_processing &&
298                     ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
299
300                         ppsc->inactive_pwrstate = ERFON;
301                         ppsc->b_in_powersavemode = false;
302
303                         _rtl_ps_inactive_ps(hw);
304                 }
305         }
306
307         spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
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  */
317 static 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(rtlpriv, COMP_POWER, DBG_LOUD,
329                          ("Delay enter Fw LPS for DHCP, ARP,"
330                           " or EAPOL exchanging state.\n"));
331                 return false;
332         }
333
334         if (mac->link_state != MAC80211_LINKED)
335                 return false;
336
337         if (mac->opmode == NL80211_IFTYPE_ADHOC)
338                 return false;
339
340         return true;
341 }
342
343 /* Change current and default preamble mode.*/
344 static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
345 {
346         struct rtl_priv *rtlpriv = rtl_priv(hw);
347         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
348         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
349         u8 rpwm_val, fw_pwrmode;
350
351         if (mac->opmode == NL80211_IFTYPE_ADHOC)
352                 return;
353
354         if (mac->link_state != MAC80211_LINKED)
355                 return;
356
357         if (ppsc->dot11_psmode == rt_psmode)
358                 return;
359
360         /* Update power save mode configured. */
361         ppsc->dot11_psmode = rt_psmode;
362
363         /*
364          *<FW control LPS>
365          *1. Enter PS mode
366          *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
367          *   cmd to set Fw into PS mode.
368          *2. Leave PS mode
369          *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active
370          *   mode and set RPWM to turn RF on.
371          */
372
373         if ((ppsc->b_fwctrl_lps) && (ppsc->b_leisure_ps) &&
374              ppsc->report_linked) {
375                 bool b_fw_current_inps;
376                 if (ppsc->dot11_psmode == EACTIVE) {
377                         RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
378                                  ("FW LPS leave ps_mode:%x\n",
379                                   FW_PS_ACTIVE_MODE));
380
381                         rpwm_val = 0x0C;        /* RF on */
382                         fw_pwrmode = FW_PS_ACTIVE_MODE;
383                         rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
384                                         (u8 *) (&rpwm_val));
385                         rtlpriv->cfg->ops->set_hw_reg(hw,
386                                         HW_VAR_H2C_FW_PWRMODE,
387                                         (u8 *) (&fw_pwrmode));
388                         b_fw_current_inps = false;
389
390                         rtlpriv->cfg->ops->set_hw_reg(hw,
391                                         HW_VAR_FW_PSMODE_STATUS,
392                                         (u8 *) (&b_fw_current_inps));
393
394                 } else {
395                         if (rtl_get_fwlps_doze(hw)) {
396                                 RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
397                                                 ("FW LPS enter ps_mode:%x\n",
398                                                  ppsc->fwctrl_psmode));
399
400                                 rpwm_val = 0x02;        /* RF off */
401                                 b_fw_current_inps = true;
402                                 rtlpriv->cfg->ops->set_hw_reg(hw,
403                                                 HW_VAR_FW_PSMODE_STATUS,
404                                                 (u8 *) (&b_fw_current_inps));
405                                 rtlpriv->cfg->ops->set_hw_reg(hw,
406                                                 HW_VAR_H2C_FW_PWRMODE,
407                                                 (u8 *) (&ppsc->fwctrl_psmode));
408
409                                 rtlpriv->cfg->ops->set_hw_reg(hw,
410                                                 HW_VAR_SET_RPWM,
411                                                 (u8 *) (&rpwm_val));
412                         } else {
413                                 /* Reset the power save related parameters. */
414                                 ppsc->dot11_psmode = EACTIVE;
415                         }
416                 }
417         }
418 }
419
420 /*Enter the leisure power save mode.*/
421 void rtl_lps_enter(struct ieee80211_hw *hw)
422 {
423         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
424         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
425         struct rtl_priv *rtlpriv = rtl_priv(hw);
426         unsigned long flag;
427
428         if (!(ppsc->b_fwctrl_lps && ppsc->b_leisure_ps))
429                 return;
430
431         if (rtlpriv->sec.being_setkey)
432                 return;
433
434         if (rtlpriv->link_info.b_busytraffic)
435                 return;
436
437         /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
438         if (mac->cnt_after_linked < 5)
439                 return;
440
441         if (mac->opmode == NL80211_IFTYPE_ADHOC)
442                 return;
443
444         if (mac->link_state != MAC80211_LINKED)
445                 return;
446
447         spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
448
449         if (ppsc->b_leisure_ps) {
450                 /* Idle for a while if we connect to AP a while ago. */
451                 if (mac->cnt_after_linked >= 2) {
452                         if (ppsc->dot11_psmode == EACTIVE) {
453                                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
454                                         ("Enter 802.11 power save mode...\n"));
455
456                                 rtl_lps_set_psmode(hw, EAUTOPS);
457                         }
458                 }
459         }
460         spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
461 }
462
463 /*Leave the leisure power save mode.*/
464 void rtl_lps_leave(struct ieee80211_hw *hw)
465 {
466         struct rtl_priv *rtlpriv = rtl_priv(hw);
467         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
468         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
469         unsigned long flag;
470
471         spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
472
473         if (ppsc->b_fwctrl_lps && ppsc->b_leisure_ps) {
474                 if (ppsc->dot11_psmode != EACTIVE) {
475
476                         /*FIX ME */
477                         rtlpriv->cfg->ops->enable_interrupt(hw);
478
479                         if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
480                             RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) &&
481                             rtlhal->interface == INTF_PCI) {
482                                 rtlpriv->intf_ops->disable_aspm(hw);
483                                 RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM);
484                         }
485
486                         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
487                                  ("Busy Traffic,Leave 802.11 power save..\n"));
488
489                         rtl_lps_set_psmode(hw, EACTIVE);
490                 }
491         }
492         spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
493 }