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