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