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> | |
e73fd15e | 25 | #include <usb_ops_linux.h> |
1cc18a22 | 26 | #include <linux/usb.h> |
95311b47 | 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. */ | |
b4ba3b57 | 73 | rtw_free_assoc_resources(padapter); |
95311b47 | 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 | 220 | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
1cc18a22 LF |
221 | bool ret = false; |
222 | ||
e017a92b | 223 | if (time_after_eq(adapter->pwrctrlpriv.ips_deny_time, jiffies)) |
1cc18a22 LF |
224 | goto exit; |
225 | ||
226 | if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || | |
227 | check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) || | |
228 | check_fwstate(pmlmepriv, WIFI_AP_STATE) || | |
2454e79a | 229 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)) |
1cc18a22 LF |
230 | goto exit; |
231 | ||
1cc18a22 LF |
232 | ret = true; |
233 | ||
234 | exit: | |
235 | return ret; | |
236 | } | |
237 | ||
238 | void rtw_ps_processor(struct adapter *padapter) | |
239 | { | |
240 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
241 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); | |
242 | enum rt_rf_power_state rfpwrstate; | |
243 | ||
244 | pwrpriv->ps_processing = true; | |
245 | ||
246 | if (pwrpriv->bips_processing) | |
247 | goto exit; | |
248 | ||
249 | if (padapter->pwrctrlpriv.bHWPwrPindetect) { | |
250 | rfpwrstate = RfOnOffDetect(padapter); | |
251 | DBG_88E("@@@@- #2 %s==> rfstate:%s\n", __func__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off"); | |
252 | ||
253 | if (rfpwrstate != pwrpriv->rf_pwrstate) { | |
254 | if (rfpwrstate == rf_off) { | |
255 | pwrpriv->change_rfpwrstate = rf_off; | |
256 | pwrpriv->brfoffbyhw = true; | |
1cc18a22 LF |
257 | rtw_hw_suspend(padapter); |
258 | } else { | |
259 | pwrpriv->change_rfpwrstate = rf_on; | |
260 | rtw_hw_resume(padapter); | |
261 | } | |
262 | DBG_88E("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on"); | |
263 | } | |
264 | pwrpriv->pwr_state_check_cnts++; | |
265 | } | |
266 | ||
267 | if (pwrpriv->ips_mode_req == IPS_NONE) | |
268 | goto exit; | |
269 | ||
5b66fb7d | 270 | if (!rtw_pwr_unassociated_idle(padapter)) |
1cc18a22 LF |
271 | goto exit; |
272 | ||
273 | if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) { | |
274 | DBG_88E("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv)); | |
275 | pwrpriv->change_rfpwrstate = rf_off; | |
276 | ||
277 | ips_enter(padapter); | |
278 | } | |
279 | exit: | |
280 | rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); | |
281 | pwrpriv->ps_processing = false; | |
1cc18a22 LF |
282 | } |
283 | ||
28af7ea8 | 284 | static void pwr_state_check_handler(unsigned long data) |
1cc18a22 | 285 | { |
28af7ea8 | 286 | struct adapter *padapter = (struct adapter *)data; |
1cc18a22 LF |
287 | rtw_ps_cmd(padapter); |
288 | } | |
289 | ||
290 | /* | |
291 | * | |
292 | * Parameters | |
293 | * padapter | |
294 | * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 | |
295 | * | |
296 | */ | |
297 | void rtw_set_rpwm(struct adapter *padapter, u8 pslv) | |
298 | { | |
299 | u8 rpwm; | |
300 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
301 | ||
1cc18a22 LF |
302 | pslv = PS_STATE(pslv); |
303 | ||
1cc18a22 LF |
304 | if (pwrpriv->btcoex_rfon) { |
305 | if (pslv < PS_STATE_S4) | |
306 | pslv = PS_STATE_S3; | |
307 | } | |
308 | ||
309 | if ((pwrpriv->rpwm == pslv)) { | |
310 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
311 | ("%s: Already set rpwm[0x%02X], new=0x%02X!\n", __func__, pwrpriv->rpwm, pslv)); | |
312 | return; | |
313 | } | |
314 | ||
315 | if ((padapter->bSurpriseRemoved) || | |
316 | (!padapter->hw_init_completed)) { | |
317 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
318 | ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", | |
319 | __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed)); | |
320 | ||
321 | pwrpriv->cpwm = PS_STATE_S4; | |
322 | ||
323 | return; | |
324 | } | |
325 | ||
326 | if (padapter->bDriverStopped) { | |
327 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
328 | ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv)); | |
329 | ||
330 | if (pslv < PS_STATE_S2) { | |
331 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
332 | ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv)); | |
333 | return; | |
334 | } | |
335 | } | |
336 | ||
337 | rpwm = pslv | pwrpriv->tog; | |
338 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, | |
339 | ("rtw_set_rpwm: rpwm=0x%02x cpwm=0x%02x\n", rpwm, pwrpriv->cpwm)); | |
340 | ||
341 | pwrpriv->rpwm = pslv; | |
342 | ||
343 | rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); | |
344 | ||
345 | pwrpriv->tog += 0x80; | |
346 | pwrpriv->cpwm = pslv; | |
1cc18a22 LF |
347 | } |
348 | ||
349 | static u8 PS_RDY_CHECK(struct adapter *padapter) | |
350 | { | |
351 | u32 curr_time, delta_time; | |
352 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
353 | struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); | |
354 | ||
355 | ||
c01fb496 | 356 | curr_time = jiffies; |
1cc18a22 LF |
357 | delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp; |
358 | ||
359 | if (delta_time < LPS_DELAY_TIME) | |
360 | return false; | |
361 | ||
362 | if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) || | |
363 | (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) || | |
364 | (check_fwstate(pmlmepriv, WIFI_AP_STATE)) || | |
365 | (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || | |
366 | (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) | |
367 | return false; | |
368 | if (pwrpriv->bInSuspend) | |
369 | return false; | |
370 | if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) { | |
371 | DBG_88E("Group handshake still in progress !!!\n"); | |
372 | return false; | |
373 | } | |
374 | return true; | |
375 | } | |
376 | ||
377 | void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode) | |
378 | { | |
379 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
1cc18a22 | 380 | |
1cc18a22 LF |
381 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, |
382 | ("%s: PowerMode=%d Smart_PS=%d\n", | |
383 | __func__, ps_mode, smart_ps)); | |
384 | ||
385 | if (ps_mode > PM_Card_Disable) { | |
386 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode)); | |
387 | return; | |
388 | } | |
389 | ||
390 | if (pwrpriv->pwr_mode == ps_mode) { | |
391 | if (PS_MODE_ACTIVE == ps_mode) | |
392 | return; | |
393 | ||
394 | if ((pwrpriv->smart_ps == smart_ps) && | |
395 | (pwrpriv->bcn_ant_mode == bcn_ant_mode)) | |
396 | return; | |
397 | } | |
398 | ||
399 | /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */ | |
400 | if (ps_mode == PS_MODE_ACTIVE) { | |
1cc18a22 LF |
401 | if (PS_RDY_CHECK(padapter)) { |
402 | DBG_88E("%s: Enter 802.11 power save\n", __func__); | |
403 | pwrpriv->bFwCurrentInPSMode = true; | |
404 | pwrpriv->pwr_mode = ps_mode; | |
405 | pwrpriv->smart_ps = smart_ps; | |
406 | pwrpriv->bcn_ant_mode = bcn_ant_mode; | |
407 | rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); | |
1cc18a22 LF |
408 | rtw_set_rpwm(padapter, PS_STATE_S2); |
409 | } | |
410 | } | |
1cc18a22 LF |
411 | } |
412 | ||
413 | /* | |
414 | * Return: | |
415 | * 0: Leave OK | |
416 | * -1: Timeout | |
417 | * -2: Other error | |
418 | */ | |
419 | s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) | |
420 | { | |
421 | u32 start_time; | |
422 | u8 bAwake = false; | |
423 | s32 err = 0; | |
424 | ||
425 | ||
c01fb496 | 426 | start_time = jiffies; |
1cc18a22 LF |
427 | while (1) { |
428 | rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); | |
429 | if (bAwake) | |
430 | break; | |
431 | ||
432 | if (padapter->bSurpriseRemoved) { | |
433 | err = -2; | |
434 | DBG_88E("%s: device surprise removed!!\n", __func__); | |
435 | break; | |
436 | } | |
437 | ||
438 | if (rtw_get_passing_time_ms(start_time) > delay_ms) { | |
439 | err = -1; | |
440 | DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); | |
441 | break; | |
442 | } | |
b2dcff2a | 443 | msleep(1); |
1cc18a22 LF |
444 | } |
445 | ||
446 | return err; | |
447 | } | |
448 | ||
449 | /* */ | |
450 | /* Description: */ | |
451 | /* Enter the leisure power save mode. */ | |
452 | /* */ | |
453 | void LPS_Enter(struct adapter *padapter) | |
454 | { | |
455 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
456 | ||
1cc18a22 LF |
457 | if (PS_RDY_CHECK(padapter) == false) |
458 | return; | |
459 | ||
460 | if (pwrpriv->bLeisurePs) { | |
461 | /* Idle for a while if we connect to AP a while ago. */ | |
462 | if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ | |
463 | if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { | |
464 | pwrpriv->bpower_saving = true; | |
465 | DBG_88E("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps); | |
466 | /* For Tenda W311R IOT issue */ | |
467 | rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0); | |
468 | } | |
469 | } else { | |
470 | pwrpriv->LpsIdleCount++; | |
471 | } | |
472 | } | |
1cc18a22 LF |
473 | } |
474 | ||
475 | #define LPS_LEAVE_TIMEOUT_MS 100 | |
476 | ||
477 | /* Description: */ | |
478 | /* Leave the leisure power save mode. */ | |
479 | void LPS_Leave(struct adapter *padapter) | |
480 | { | |
481 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
482 | ||
1cc18a22 LF |
483 | if (pwrpriv->bLeisurePs) { |
484 | if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { | |
485 | rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0); | |
486 | ||
487 | if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) | |
488 | LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS); | |
489 | } | |
490 | } | |
491 | ||
492 | pwrpriv->bpower_saving = false; | |
1cc18a22 LF |
493 | } |
494 | ||
495 | /* */ | |
496 | /* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */ | |
497 | /* Move code to function by tynli. 2010.03.26. */ | |
498 | /* */ | |
499 | void LeaveAllPowerSaveMode(struct adapter *Adapter) | |
500 | { | |
501 | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); | |
502 | u8 enqueue = 0; | |
503 | ||
2454e79a | 504 | if (check_fwstate(pmlmepriv, _FW_LINKED)) |
1cc18a22 | 505 | rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); |
1cc18a22 LF |
506 | } |
507 | ||
508 | void rtw_init_pwrctrl_priv(struct adapter *padapter) | |
509 | { | |
510 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
511 | ||
1cc18a22 LF |
512 | _init_pwrlock(&pwrctrlpriv->lock); |
513 | pwrctrlpriv->rf_pwrstate = rf_on; | |
514 | pwrctrlpriv->ips_enter_cnts = 0; | |
515 | pwrctrlpriv->ips_leave_cnts = 0; | |
516 | pwrctrlpriv->bips_processing = false; | |
517 | ||
518 | pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; | |
519 | pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; | |
520 | ||
521 | pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; | |
522 | pwrctrlpriv->pwr_state_check_cnts = 0; | |
523 | pwrctrlpriv->bInternalAutoSuspend = false; | |
524 | pwrctrlpriv->bInSuspend = false; | |
525 | pwrctrlpriv->bkeepfwalive = false; | |
526 | ||
527 | pwrctrlpriv->LpsIdleCount = 0; | |
528 | if (padapter->registrypriv.mp_mode == 1) | |
2adc8c46 | 529 | pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE; |
1cc18a22 LF |
530 | else |
531 | pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ | |
532 | pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; | |
533 | ||
534 | pwrctrlpriv->bFwCurrentInPSMode = false; | |
535 | ||
536 | pwrctrlpriv->rpwm = 0; | |
537 | pwrctrlpriv->cpwm = PS_STATE_S4; | |
538 | ||
539 | pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; | |
540 | pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; | |
541 | pwrctrlpriv->bcn_ant_mode = 0; | |
542 | ||
543 | pwrctrlpriv->tog = 0x80; | |
544 | ||
545 | pwrctrlpriv->btcoex_rfon = false; | |
546 | ||
28af7ea8 VT |
547 | setup_timer(&pwrctrlpriv->pwr_state_check_timer, |
548 | pwr_state_check_handler, | |
549 | (unsigned long)padapter); | |
1cc18a22 LF |
550 | } |
551 | ||
1cc18a22 LF |
552 | /* |
553 | * rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend | |
554 | * @adapter: pointer to struct adapter structure | |
40a46d8b | 555 | * @ips_deffer_ms: the ms will prevent from falling into IPS after wakeup |
1cc18a22 LF |
556 | * Return _SUCCESS or _FAIL |
557 | */ | |
558 | ||
559 | int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller) | |
560 | { | |
561 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
562 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
e017a92b | 563 | unsigned long expires; |
1cc18a22 LF |
564 | int ret = _SUCCESS; |
565 | ||
ace05013 | 566 | expires = jiffies + msecs_to_jiffies(ips_deffer_ms); |
e017a92b | 567 | if (time_before(pwrpriv->ips_deny_time, expires)) |
ace05013 | 568 | pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); |
1cc18a22 LF |
569 | |
570 | { | |
c01fb496 | 571 | u32 start = jiffies; |
1cc18a22 LF |
572 | if (pwrpriv->ps_processing) { |
573 | DBG_88E("%s wait ps_processing...\n", __func__); | |
574 | while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000) | |
86ca02da | 575 | usleep_range(1000, 3000); |
1cc18a22 LF |
576 | if (pwrpriv->ps_processing) |
577 | DBG_88E("%s wait ps_processing timeout\n", __func__); | |
578 | else | |
579 | DBG_88E("%s wait ps_processing done\n", __func__); | |
580 | } | |
581 | } | |
582 | ||
583 | /* System suspend is not allowed to wakeup */ | |
584 | if ((!pwrpriv->bInternalAutoSuspend) && (pwrpriv->bInSuspend)) { | |
585 | ret = _FAIL; | |
586 | goto exit; | |
587 | } | |
588 | ||
589 | /* block??? */ | |
590 | if ((pwrpriv->bInternalAutoSuspend) && (padapter->net_closed)) { | |
591 | ret = _FAIL; | |
592 | goto exit; | |
593 | } | |
594 | ||
595 | /* I think this should be check in IPS, LPS, autosuspend functions... */ | |
596 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { | |
597 | ret = _SUCCESS; | |
598 | goto exit; | |
599 | } | |
600 | if (rf_off == pwrpriv->rf_pwrstate) { | |
601 | DBG_88E("%s call ips_leave....\n", __func__); | |
602 | if (_FAIL == ips_leave(padapter)) { | |
603 | DBG_88E("======> ips_leave fail.............\n"); | |
604 | ret = _FAIL; | |
605 | goto exit; | |
606 | } | |
607 | } | |
608 | ||
609 | /* TODO: the following checking need to be merged... */ | |
610 | if (padapter->bDriverStopped || !padapter->bup || | |
611 | !padapter->hw_init_completed) { | |
612 | DBG_88E("%s: bDriverStopped=%d, bup=%d, hw_init_completed =%u\n" | |
613 | , caller | |
614 | , padapter->bDriverStopped | |
615 | , padapter->bup | |
616 | , padapter->hw_init_completed); | |
617 | ret = false; | |
618 | goto exit; | |
619 | } | |
620 | ||
621 | exit: | |
ace05013 | 622 | expires = jiffies + msecs_to_jiffies(ips_deffer_ms); |
e017a92b | 623 | if (time_before(pwrpriv->ips_deny_time, expires)) |
ace05013 | 624 | pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); |
1cc18a22 LF |
625 | return ret; |
626 | } | |
627 | ||
628 | int rtw_pm_set_lps(struct adapter *padapter, u8 mode) | |
629 | { | |
630 | int ret = 0; | |
631 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
632 | ||
633 | if (mode < PS_MODE_NUM) { | |
634 | if (pwrctrlpriv->power_mgnt != mode) { | |
635 | if (PS_MODE_ACTIVE == mode) | |
636 | LeaveAllPowerSaveMode(padapter); | |
637 | else | |
638 | pwrctrlpriv->LpsIdleCount = 2; | |
639 | pwrctrlpriv->power_mgnt = mode; | |
640 | pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; | |
641 | } | |
642 | } else { | |
643 | ret = -EINVAL; | |
644 | } | |
645 | ||
646 | return ret; | |
647 | } | |
648 | ||
649 | int rtw_pm_set_ips(struct adapter *padapter, u8 mode) | |
650 | { | |
651 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
652 | ||
653 | if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { | |
654 | rtw_ips_mode_req(pwrctrlpriv, mode); | |
655 | DBG_88E("%s %s\n", __func__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2"); | |
656 | return 0; | |
657 | } else if (mode == IPS_NONE) { | |
658 | rtw_ips_mode_req(pwrctrlpriv, mode); | |
659 | DBG_88E("%s %s\n", __func__, "IPS_NONE"); | |
660 | if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter))) | |
661 | return -EFAULT; | |
662 | } else { | |
663 | return -EINVAL; | |
664 | } | |
665 | return 0; | |
666 | } |