]>
Commit | Line | Data |
---|---|---|
1cc18a22 LF |
1 | /****************************************************************************** |
2 | * | |
3 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. | |
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 | * | |
19 | ******************************************************************************/ | |
20 | #define _RTW_PWRCTRL_C_ | |
21 | ||
22 | #include <osdep_service.h> | |
23 | #include <drv_types.h> | |
24 | #include <osdep_intf.h> | |
25 | #include <linux/usb.h> | |
95311b47 | 26 | #include <usb_osintf.h> |
27 | ||
28 | static int rtw_hw_suspend(struct adapter *padapter) | |
29 | { | |
30 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
31 | struct net_device *pnetdev = padapter->pnetdev; | |
32 | ||
33 | ||
34 | if ((!padapter->bup) || (padapter->bDriverStopped) || | |
35 | (padapter->bSurpriseRemoved)) { | |
36 | DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", | |
37 | padapter->bup, padapter->bDriverStopped, | |
38 | padapter->bSurpriseRemoved); | |
39 | goto error_exit; | |
40 | } | |
41 | ||
42 | /* system suspend */ | |
43 | LeaveAllPowerSaveMode(padapter); | |
44 | ||
45 | DBG_88E("==> rtw_hw_suspend\n"); | |
46 | _enter_pwrlock(&pwrpriv->lock); | |
47 | pwrpriv->bips_processing = true; | |
48 | /* s1. */ | |
49 | if (pnetdev) { | |
50 | netif_carrier_off(pnetdev); | |
51 | netif_tx_stop_all_queues(pnetdev); | |
52 | } | |
53 | ||
54 | /* s2. */ | |
55 | rtw_disassoc_cmd(padapter, 500, false); | |
56 | ||
57 | /* s2-2. indicate disconnect to os */ | |
58 | { | |
59 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
60 | ||
61 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { | |
62 | _clr_fwstate_(pmlmepriv, _FW_LINKED); | |
63 | ||
64 | rtw_led_control(padapter, LED_CTL_NO_LINK); | |
65 | ||
66 | rtw_os_indicate_disconnect(padapter); | |
67 | ||
68 | /* donnot enqueue cmd */ | |
69 | rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 0); | |
70 | } | |
71 | } | |
72 | /* s2-3. */ | |
73 | rtw_free_assoc_resources(padapter, 1); | |
74 | ||
75 | /* s2-4. */ | |
76 | rtw_free_network_queue(padapter, true); | |
77 | rtw_ips_dev_unload(padapter); | |
78 | pwrpriv->rf_pwrstate = rf_off; | |
79 | pwrpriv->bips_processing = false; | |
80 | ||
81 | _exit_pwrlock(&pwrpriv->lock); | |
82 | ||
83 | return 0; | |
84 | ||
85 | error_exit: | |
86 | DBG_88E("%s, failed\n", __func__); | |
87 | return -1; | |
88 | } | |
89 | ||
90 | static int rtw_hw_resume(struct adapter *padapter) | |
91 | { | |
92 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
93 | struct net_device *pnetdev = padapter->pnetdev; | |
94 | ||
95 | ||
96 | /* system resume */ | |
97 | DBG_88E("==> rtw_hw_resume\n"); | |
98 | _enter_pwrlock(&pwrpriv->lock); | |
99 | pwrpriv->bips_processing = true; | |
100 | rtw_reset_drv_sw(padapter); | |
101 | ||
102 | if (pm_netdev_open(pnetdev, false) != 0) { | |
103 | _exit_pwrlock(&pwrpriv->lock); | |
104 | goto error_exit; | |
105 | } | |
106 | ||
107 | netif_device_attach(pnetdev); | |
108 | netif_carrier_on(pnetdev); | |
109 | ||
110 | if (!netif_queue_stopped(pnetdev)) | |
111 | netif_start_queue(pnetdev); | |
112 | else | |
113 | netif_wake_queue(pnetdev); | |
114 | ||
115 | pwrpriv->bkeepfwalive = false; | |
116 | pwrpriv->brfoffbyhw = false; | |
117 | ||
118 | pwrpriv->rf_pwrstate = rf_on; | |
119 | pwrpriv->bips_processing = false; | |
120 | ||
121 | _exit_pwrlock(&pwrpriv->lock); | |
122 | ||
123 | ||
124 | return 0; | |
125 | error_exit: | |
126 | DBG_88E("%s, Open net dev failed\n", __func__); | |
127 | return -1; | |
128 | } | |
1cc18a22 LF |
129 | |
130 | void ips_enter(struct adapter *padapter) | |
131 | { | |
132 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
133 | struct xmit_priv *pxmit_priv = &padapter->xmitpriv; | |
134 | ||
135 | if (padapter->registrypriv.mp_mode == 1) | |
136 | return; | |
137 | ||
138 | if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || | |
139 | pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { | |
140 | DBG_88E_LEVEL(_drv_info_, "There are some pkts to transmit\n"); | |
141 | DBG_88E_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", | |
142 | pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); | |
143 | return; | |
144 | } | |
145 | ||
146 | _enter_pwrlock(&pwrpriv->lock); | |
147 | ||
148 | pwrpriv->bips_processing = true; | |
149 | ||
150 | /* syn ips_mode with request */ | |
151 | pwrpriv->ips_mode = pwrpriv->ips_mode_req; | |
152 | ||
153 | pwrpriv->ips_enter_cnts++; | |
154 | DBG_88E("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts); | |
155 | if (rf_off == pwrpriv->change_rfpwrstate) { | |
156 | pwrpriv->bpower_saving = true; | |
157 | DBG_88E_LEVEL(_drv_info_, "nolinked power save enter\n"); | |
158 | ||
159 | if (pwrpriv->ips_mode == IPS_LEVEL_2) | |
160 | pwrpriv->bkeepfwalive = true; | |
161 | ||
162 | rtw_ips_pwr_down(padapter); | |
163 | pwrpriv->rf_pwrstate = rf_off; | |
164 | } | |
165 | pwrpriv->bips_processing = false; | |
166 | ||
167 | _exit_pwrlock(&pwrpriv->lock); | |
168 | } | |
169 | ||
170 | int ips_leave(struct adapter *padapter) | |
171 | { | |
172 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
173 | struct security_priv *psecuritypriv = &(padapter->securitypriv); | |
174 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); | |
175 | int result = _SUCCESS; | |
176 | int keyid; | |
177 | ||
178 | ||
179 | _enter_pwrlock(&pwrpriv->lock); | |
180 | ||
181 | if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) { | |
182 | pwrpriv->bips_processing = true; | |
183 | pwrpriv->change_rfpwrstate = rf_on; | |
184 | pwrpriv->ips_leave_cnts++; | |
185 | DBG_88E("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts); | |
186 | ||
187 | result = rtw_ips_pwr_up(padapter); | |
188 | if (result == _SUCCESS) { | |
189 | pwrpriv->rf_pwrstate = rf_on; | |
190 | } | |
191 | DBG_88E_LEVEL(_drv_info_, "nolinked power save leave\n"); | |
192 | ||
193 | if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) || (_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm)) { | |
194 | DBG_88E("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing); | |
195 | set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); | |
196 | for (keyid = 0; keyid < 4; keyid++) { | |
197 | if (pmlmepriv->key_mask & BIT(keyid)) { | |
198 | if (keyid == psecuritypriv->dot11PrivacyKeyIndex) | |
199 | result = rtw_set_key(padapter, psecuritypriv, keyid, 1); | |
200 | else | |
201 | result = rtw_set_key(padapter, psecuritypriv, keyid, 0); | |
202 | } | |
203 | } | |
204 | } | |
205 | ||
99ecfb06 | 206 | DBG_88E("==> ips_leave.....LED(0x%08x)...\n", usb_read32(padapter, 0x4c)); |
1cc18a22 LF |
207 | pwrpriv->bips_processing = false; |
208 | ||
209 | pwrpriv->bkeepfwalive = false; | |
210 | pwrpriv->bpower_saving = false; | |
211 | } | |
212 | ||
213 | _exit_pwrlock(&pwrpriv->lock); | |
214 | ||
215 | return result; | |
216 | } | |
217 | ||
218 | static bool rtw_pwr_unassociated_idle(struct adapter *adapter) | |
219 | { | |
1cc18a22 LF |
220 | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
221 | #ifdef CONFIG_88EU_P2P | |
222 | struct wifidirect_info *pwdinfo = &(adapter->wdinfo); | |
223 | #endif | |
224 | ||
225 | bool ret = false; | |
226 | ||
e017a92b | 227 | if (time_after_eq(adapter->pwrctrlpriv.ips_deny_time, jiffies)) |
1cc18a22 LF |
228 | goto exit; |
229 | ||
230 | if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || | |
231 | check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) || | |
232 | check_fwstate(pmlmepriv, WIFI_AP_STATE) || | |
233 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) || | |
234 | #if defined(CONFIG_88EU_P2P) | |
235 | !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) | |
236 | #else | |
237 | 0) | |
238 | #endif | |
239 | goto exit; | |
240 | ||
1cc18a22 LF |
241 | ret = true; |
242 | ||
243 | exit: | |
244 | return ret; | |
245 | } | |
246 | ||
247 | void rtw_ps_processor(struct adapter *padapter) | |
248 | { | |
249 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
250 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); | |
251 | enum rt_rf_power_state rfpwrstate; | |
252 | ||
253 | pwrpriv->ps_processing = true; | |
254 | ||
255 | if (pwrpriv->bips_processing) | |
256 | goto exit; | |
257 | ||
258 | if (padapter->pwrctrlpriv.bHWPwrPindetect) { | |
259 | rfpwrstate = RfOnOffDetect(padapter); | |
260 | DBG_88E("@@@@- #2 %s==> rfstate:%s\n", __func__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off"); | |
261 | ||
262 | if (rfpwrstate != pwrpriv->rf_pwrstate) { | |
263 | if (rfpwrstate == rf_off) { | |
264 | pwrpriv->change_rfpwrstate = rf_off; | |
265 | pwrpriv->brfoffbyhw = true; | |
1cc18a22 LF |
266 | rtw_hw_suspend(padapter); |
267 | } else { | |
268 | pwrpriv->change_rfpwrstate = rf_on; | |
269 | rtw_hw_resume(padapter); | |
270 | } | |
271 | DBG_88E("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on"); | |
272 | } | |
273 | pwrpriv->pwr_state_check_cnts++; | |
274 | } | |
275 | ||
276 | if (pwrpriv->ips_mode_req == IPS_NONE) | |
277 | goto exit; | |
278 | ||
5b66fb7d | 279 | if (!rtw_pwr_unassociated_idle(padapter)) |
1cc18a22 LF |
280 | goto exit; |
281 | ||
282 | if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) { | |
283 | DBG_88E("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv)); | |
284 | pwrpriv->change_rfpwrstate = rf_off; | |
285 | ||
286 | ips_enter(padapter); | |
287 | } | |
288 | exit: | |
289 | rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); | |
290 | pwrpriv->ps_processing = false; | |
291 | return; | |
292 | } | |
293 | ||
294 | static void pwr_state_check_handler(void *FunctionContext) | |
295 | { | |
296 | struct adapter *padapter = (struct adapter *)FunctionContext; | |
297 | rtw_ps_cmd(padapter); | |
298 | } | |
299 | ||
300 | /* | |
301 | * | |
302 | * Parameters | |
303 | * padapter | |
304 | * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 | |
305 | * | |
306 | */ | |
307 | void rtw_set_rpwm(struct adapter *padapter, u8 pslv) | |
308 | { | |
309 | u8 rpwm; | |
310 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
311 | ||
1cc18a22 LF |
312 | pslv = PS_STATE(pslv); |
313 | ||
1cc18a22 LF |
314 | if (pwrpriv->btcoex_rfon) { |
315 | if (pslv < PS_STATE_S4) | |
316 | pslv = PS_STATE_S3; | |
317 | } | |
318 | ||
319 | if ((pwrpriv->rpwm == pslv)) { | |
320 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
321 | ("%s: Already set rpwm[0x%02X], new=0x%02X!\n", __func__, pwrpriv->rpwm, pslv)); | |
322 | return; | |
323 | } | |
324 | ||
325 | if ((padapter->bSurpriseRemoved) || | |
326 | (!padapter->hw_init_completed)) { | |
327 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
328 | ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", | |
329 | __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed)); | |
330 | ||
331 | pwrpriv->cpwm = PS_STATE_S4; | |
332 | ||
333 | return; | |
334 | } | |
335 | ||
336 | if (padapter->bDriverStopped) { | |
337 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
338 | ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv)); | |
339 | ||
340 | if (pslv < PS_STATE_S2) { | |
341 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
342 | ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv)); | |
343 | return; | |
344 | } | |
345 | } | |
346 | ||
347 | rpwm = pslv | pwrpriv->tog; | |
348 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, | |
349 | ("rtw_set_rpwm: rpwm=0x%02x cpwm=0x%02x\n", rpwm, pwrpriv->cpwm)); | |
350 | ||
351 | pwrpriv->rpwm = pslv; | |
352 | ||
353 | rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); | |
354 | ||
355 | pwrpriv->tog += 0x80; | |
356 | pwrpriv->cpwm = pslv; | |
1cc18a22 LF |
357 | } |
358 | ||
359 | static u8 PS_RDY_CHECK(struct adapter *padapter) | |
360 | { | |
361 | u32 curr_time, delta_time; | |
362 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
363 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); | |
364 | ||
365 | ||
c01fb496 | 366 | curr_time = jiffies; |
1cc18a22 LF |
367 | delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp; |
368 | ||
369 | if (delta_time < LPS_DELAY_TIME) | |
370 | return false; | |
371 | ||
372 | if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) || | |
373 | (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) || | |
374 | (check_fwstate(pmlmepriv, WIFI_AP_STATE)) || | |
375 | (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || | |
376 | (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) | |
377 | return false; | |
378 | if (pwrpriv->bInSuspend) | |
379 | return false; | |
380 | if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) { | |
381 | DBG_88E("Group handshake still in progress !!!\n"); | |
382 | return false; | |
383 | } | |
384 | return true; | |
385 | } | |
386 | ||
387 | void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode) | |
388 | { | |
389 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
390 | #ifdef CONFIG_88EU_P2P | |
391 | struct wifidirect_info *pwdinfo = &(padapter->wdinfo); | |
392 | #endif /* CONFIG_88EU_P2P */ | |
393 | ||
1cc18a22 LF |
394 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, |
395 | ("%s: PowerMode=%d Smart_PS=%d\n", | |
396 | __func__, ps_mode, smart_ps)); | |
397 | ||
398 | if (ps_mode > PM_Card_Disable) { | |
399 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode)); | |
400 | return; | |
401 | } | |
402 | ||
403 | if (pwrpriv->pwr_mode == ps_mode) { | |
404 | if (PS_MODE_ACTIVE == ps_mode) | |
405 | return; | |
406 | ||
407 | if ((pwrpriv->smart_ps == smart_ps) && | |
408 | (pwrpriv->bcn_ant_mode == bcn_ant_mode)) | |
409 | return; | |
410 | } | |
411 | ||
412 | /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */ | |
413 | if (ps_mode == PS_MODE_ACTIVE) { | |
414 | #ifdef CONFIG_88EU_P2P | |
415 | if (pwdinfo->opp_ps == 0) { | |
416 | DBG_88E("rtw_set_ps_mode: Leave 802.11 power save\n"); | |
417 | pwrpriv->pwr_mode = ps_mode; | |
418 | rtw_set_rpwm(padapter, PS_STATE_S4); | |
419 | rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); | |
420 | pwrpriv->bFwCurrentInPSMode = false; | |
421 | } | |
422 | } else { | |
423 | #endif /* CONFIG_88EU_P2P */ | |
424 | if (PS_RDY_CHECK(padapter)) { | |
425 | DBG_88E("%s: Enter 802.11 power save\n", __func__); | |
426 | pwrpriv->bFwCurrentInPSMode = true; | |
427 | pwrpriv->pwr_mode = ps_mode; | |
428 | pwrpriv->smart_ps = smart_ps; | |
429 | pwrpriv->bcn_ant_mode = bcn_ant_mode; | |
430 | rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); | |
431 | ||
432 | #ifdef CONFIG_88EU_P2P | |
433 | /* Set CTWindow after LPS */ | |
434 | if (pwdinfo->opp_ps == 1) | |
435 | p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0); | |
436 | #endif /* CONFIG_88EU_P2P */ | |
437 | ||
438 | rtw_set_rpwm(padapter, PS_STATE_S2); | |
439 | } | |
440 | } | |
1cc18a22 LF |
441 | } |
442 | ||
443 | /* | |
444 | * Return: | |
445 | * 0: Leave OK | |
446 | * -1: Timeout | |
447 | * -2: Other error | |
448 | */ | |
449 | s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) | |
450 | { | |
451 | u32 start_time; | |
452 | u8 bAwake = false; | |
453 | s32 err = 0; | |
454 | ||
455 | ||
c01fb496 | 456 | start_time = jiffies; |
1cc18a22 LF |
457 | while (1) { |
458 | rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); | |
459 | if (bAwake) | |
460 | break; | |
461 | ||
462 | if (padapter->bSurpriseRemoved) { | |
463 | err = -2; | |
464 | DBG_88E("%s: device surprise removed!!\n", __func__); | |
465 | break; | |
466 | } | |
467 | ||
468 | if (rtw_get_passing_time_ms(start_time) > delay_ms) { | |
469 | err = -1; | |
470 | DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); | |
471 | break; | |
472 | } | |
b2dcff2a | 473 | msleep(1); |
1cc18a22 LF |
474 | } |
475 | ||
476 | return err; | |
477 | } | |
478 | ||
479 | /* */ | |
480 | /* Description: */ | |
481 | /* Enter the leisure power save mode. */ | |
482 | /* */ | |
483 | void LPS_Enter(struct adapter *padapter) | |
484 | { | |
485 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
486 | ||
1cc18a22 LF |
487 | if (PS_RDY_CHECK(padapter) == false) |
488 | return; | |
489 | ||
490 | if (pwrpriv->bLeisurePs) { | |
491 | /* Idle for a while if we connect to AP a while ago. */ | |
492 | if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ | |
493 | if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { | |
494 | pwrpriv->bpower_saving = true; | |
495 | DBG_88E("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps); | |
496 | /* For Tenda W311R IOT issue */ | |
497 | rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0); | |
498 | } | |
499 | } else { | |
500 | pwrpriv->LpsIdleCount++; | |
501 | } | |
502 | } | |
1cc18a22 LF |
503 | } |
504 | ||
505 | #define LPS_LEAVE_TIMEOUT_MS 100 | |
506 | ||
507 | /* Description: */ | |
508 | /* Leave the leisure power save mode. */ | |
509 | void LPS_Leave(struct adapter *padapter) | |
510 | { | |
511 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
512 | ||
1cc18a22 LF |
513 | if (pwrpriv->bLeisurePs) { |
514 | if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { | |
515 | rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); | |
516 | ||
517 | if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) | |
518 | LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS); | |
519 | } | |
520 | } | |
521 | ||
522 | pwrpriv->bpower_saving = false; | |
1cc18a22 LF |
523 | } |
524 | ||
525 | /* */ | |
526 | /* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */ | |
527 | /* Move code to function by tynli. 2010.03.26. */ | |
528 | /* */ | |
529 | void LeaveAllPowerSaveMode(struct adapter *Adapter) | |
530 | { | |
531 | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); | |
532 | u8 enqueue = 0; | |
533 | ||
1cc18a22 LF |
534 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */ |
535 | p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue); | |
536 | ||
537 | rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); | |
538 | } | |
1cc18a22 LF |
539 | } |
540 | ||
541 | void rtw_init_pwrctrl_priv(struct adapter *padapter) | |
542 | { | |
543 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
544 | ||
1cc18a22 LF |
545 | _init_pwrlock(&pwrctrlpriv->lock); |
546 | pwrctrlpriv->rf_pwrstate = rf_on; | |
547 | pwrctrlpriv->ips_enter_cnts = 0; | |
548 | pwrctrlpriv->ips_leave_cnts = 0; | |
549 | pwrctrlpriv->bips_processing = false; | |
550 | ||
551 | pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; | |
552 | pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; | |
553 | ||
554 | pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; | |
555 | pwrctrlpriv->pwr_state_check_cnts = 0; | |
556 | pwrctrlpriv->bInternalAutoSuspend = false; | |
557 | pwrctrlpriv->bInSuspend = false; | |
558 | pwrctrlpriv->bkeepfwalive = false; | |
559 | ||
560 | pwrctrlpriv->LpsIdleCount = 0; | |
561 | if (padapter->registrypriv.mp_mode == 1) | |
562 | pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE ; | |
563 | else | |
564 | pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ | |
565 | pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; | |
566 | ||
567 | pwrctrlpriv->bFwCurrentInPSMode = false; | |
568 | ||
569 | pwrctrlpriv->rpwm = 0; | |
570 | pwrctrlpriv->cpwm = PS_STATE_S4; | |
571 | ||
572 | pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; | |
573 | pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; | |
574 | pwrctrlpriv->bcn_ant_mode = 0; | |
575 | ||
576 | pwrctrlpriv->tog = 0x80; | |
577 | ||
578 | pwrctrlpriv->btcoex_rfon = false; | |
579 | ||
580 | _init_timer(&(pwrctrlpriv->pwr_state_check_timer), padapter->pnetdev, pwr_state_check_handler, (u8 *)padapter); | |
1cc18a22 LF |
581 | } |
582 | ||
1cc18a22 LF |
583 | inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms) |
584 | { | |
585 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
c01fb496 | 586 | pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ms); |
1cc18a22 LF |
587 | } |
588 | ||
589 | /* | |
590 | * rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend | |
591 | * @adapter: pointer to struct adapter structure | |
40a46d8b | 592 | * @ips_deffer_ms: the ms will prevent from falling into IPS after wakeup |
1cc18a22 LF |
593 | * Return _SUCCESS or _FAIL |
594 | */ | |
595 | ||
596 | int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller) | |
597 | { | |
598 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
599 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
e017a92b | 600 | unsigned long expires; |
1cc18a22 LF |
601 | int ret = _SUCCESS; |
602 | ||
e017a92b MS |
603 | expires = jiffies + rtw_ms_to_systime(ips_deffer_ms); |
604 | if (time_before(pwrpriv->ips_deny_time, expires)) | |
c01fb496 | 605 | pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ips_deffer_ms); |
1cc18a22 LF |
606 | |
607 | { | |
c01fb496 | 608 | u32 start = jiffies; |
1cc18a22 LF |
609 | if (pwrpriv->ps_processing) { |
610 | DBG_88E("%s wait ps_processing...\n", __func__); | |
611 | while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000) | |
0da46e6b | 612 | msleep(10); |
1cc18a22 LF |
613 | if (pwrpriv->ps_processing) |
614 | DBG_88E("%s wait ps_processing timeout\n", __func__); | |
615 | else | |
616 | DBG_88E("%s wait ps_processing done\n", __func__); | |
617 | } | |
618 | } | |
619 | ||
620 | /* System suspend is not allowed to wakeup */ | |
621 | if ((!pwrpriv->bInternalAutoSuspend) && (pwrpriv->bInSuspend)) { | |
622 | ret = _FAIL; | |
623 | goto exit; | |
624 | } | |
625 | ||
626 | /* block??? */ | |
627 | if ((pwrpriv->bInternalAutoSuspend) && (padapter->net_closed)) { | |
628 | ret = _FAIL; | |
629 | goto exit; | |
630 | } | |
631 | ||
632 | /* I think this should be check in IPS, LPS, autosuspend functions... */ | |
633 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { | |
634 | ret = _SUCCESS; | |
635 | goto exit; | |
636 | } | |
637 | if (rf_off == pwrpriv->rf_pwrstate) { | |
638 | DBG_88E("%s call ips_leave....\n", __func__); | |
639 | if (_FAIL == ips_leave(padapter)) { | |
640 | DBG_88E("======> ips_leave fail.............\n"); | |
641 | ret = _FAIL; | |
642 | goto exit; | |
643 | } | |
644 | } | |
645 | ||
646 | /* TODO: the following checking need to be merged... */ | |
647 | if (padapter->bDriverStopped || !padapter->bup || | |
648 | !padapter->hw_init_completed) { | |
649 | DBG_88E("%s: bDriverStopped=%d, bup=%d, hw_init_completed =%u\n" | |
650 | , caller | |
651 | , padapter->bDriverStopped | |
652 | , padapter->bup | |
653 | , padapter->hw_init_completed); | |
654 | ret = false; | |
655 | goto exit; | |
656 | } | |
657 | ||
658 | exit: | |
e017a92b MS |
659 | expires = jiffies + rtw_ms_to_systime(ips_deffer_ms); |
660 | if (time_before(pwrpriv->ips_deny_time, expires)) | |
c01fb496 | 661 | pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ips_deffer_ms); |
1cc18a22 LF |
662 | return ret; |
663 | } | |
664 | ||
665 | int rtw_pm_set_lps(struct adapter *padapter, u8 mode) | |
666 | { | |
667 | int ret = 0; | |
668 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
669 | ||
670 | if (mode < PS_MODE_NUM) { | |
671 | if (pwrctrlpriv->power_mgnt != mode) { | |
672 | if (PS_MODE_ACTIVE == mode) | |
673 | LeaveAllPowerSaveMode(padapter); | |
674 | else | |
675 | pwrctrlpriv->LpsIdleCount = 2; | |
676 | pwrctrlpriv->power_mgnt = mode; | |
677 | pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; | |
678 | } | |
679 | } else { | |
680 | ret = -EINVAL; | |
681 | } | |
682 | ||
683 | return ret; | |
684 | } | |
685 | ||
686 | int rtw_pm_set_ips(struct adapter *padapter, u8 mode) | |
687 | { | |
688 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
689 | ||
690 | if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { | |
691 | rtw_ips_mode_req(pwrctrlpriv, mode); | |
692 | DBG_88E("%s %s\n", __func__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2"); | |
693 | return 0; | |
694 | } else if (mode == IPS_NONE) { | |
695 | rtw_ips_mode_req(pwrctrlpriv, mode); | |
696 | DBG_88E("%s %s\n", __func__, "IPS_NONE"); | |
697 | if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter))) | |
698 | return -EFAULT; | |
699 | } else { | |
700 | return -EINVAL; | |
701 | } | |
702 | return 0; | |
703 | } |