Commit | Line | Data |
---|---|---|
5e93f352 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 | ******************************************************************************/ | |
15 | #define _RTW_PWRCTRL_C_ | |
16 | ||
17 | #include <osdep_service.h> | |
18 | #include <drv_types.h> | |
19 | #include <osdep_intf.h> | |
88cdc943 | 20 | #include <rtl8723a_cmd.h> |
96808173 | 21 | #include <rtw_sreset.h> |
5e93f352 | 22 | |
280e7a0b | 23 | #include <rtl8723a_bt_intf.h> |
050abc45 | 24 | #include <usb_ops_linux.h> |
5e93f352 LF |
25 | |
26 | void ips_enter23a(struct rtw_adapter * padapter) | |
27 | { | |
28 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
29 | ||
30 | down(&pwrpriv->lock); | |
31 | ||
32 | pwrpriv->bips_processing = true; | |
33 | ||
34 | /* syn ips_mode with request */ | |
35 | pwrpriv->ips_mode = pwrpriv->ips_mode_req; | |
36 | ||
37 | pwrpriv->ips_enter23a_cnts++; | |
38 | DBG_8723A("==>ips_enter23a cnts:%d\n", pwrpriv->ips_enter23a_cnts); | |
280e7a0b JS |
39 | rtl8723a_BT_disable_coexist(padapter); |
40 | ||
d8ab7e84 | 41 | if (pwrpriv->change_rfpwrstate == rf_off) { |
5e93f352 LF |
42 | pwrpriv->bpower_saving = true; |
43 | DBG_8723A_LEVEL(_drv_always_, "nolinked power save enter\n"); | |
44 | ||
45 | if (pwrpriv->ips_mode == IPS_LEVEL_2) | |
46 | pwrpriv->bkeepfwalive = true; | |
47 | ||
48 | rtw_ips_pwr_down23a(padapter); | |
49 | pwrpriv->rf_pwrstate = rf_off; | |
50 | } | |
51 | pwrpriv->bips_processing = false; | |
52 | ||
53 | up(&pwrpriv->lock); | |
54 | } | |
55 | ||
56 | int ips_leave23a(struct rtw_adapter * padapter) | |
57 | { | |
58 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
59 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
60 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
61 | int result = _SUCCESS; | |
62 | int keyid; | |
63 | ||
64 | down(&pwrpriv->lock); | |
65 | ||
d8ab7e84 | 66 | if (pwrpriv->rf_pwrstate == rf_off && !pwrpriv->bips_processing) { |
5e93f352 LF |
67 | pwrpriv->bips_processing = true; |
68 | pwrpriv->change_rfpwrstate = rf_on; | |
69 | pwrpriv->ips_leave23a_cnts++; | |
d8ab7e84 JS |
70 | DBG_8723A("==>ips_leave23a cnts:%d\n", |
71 | pwrpriv->ips_leave23a_cnts); | |
5e93f352 | 72 | |
d8ab7e84 JS |
73 | result = rtw_ips_pwr_up23a(padapter); |
74 | if (result == _SUCCESS) | |
5e93f352 | 75 | pwrpriv->rf_pwrstate = rf_on; |
d8ab7e84 | 76 | |
5e93f352 LF |
77 | DBG_8723A_LEVEL(_drv_always_, "nolinked power save leave\n"); |
78 | ||
9e3d6df2 JS |
79 | if (psecuritypriv->dot11PrivacyAlgrthm == |
80 | WLAN_CIPHER_SUITE_WEP40 || | |
81 | psecuritypriv->dot11PrivacyAlgrthm == | |
82 | WLAN_CIPHER_SUITE_WEP104) { | |
d8ab7e84 JS |
83 | DBG_8723A("==>%s, channel(%d), processing(%x)\n", |
84 | __func__, padapter->mlmeextpriv.cur_channel, | |
85 | pwrpriv->bips_processing); | |
86 | set_channel_bwmode23a(padapter, | |
87 | padapter->mlmeextpriv.cur_channel, | |
88 | HAL_PRIME_CHNL_OFFSET_DONT_CARE, | |
89 | HT_CHANNEL_WIDTH_20); | |
4e489d91 JS |
90 | for (keyid = 0; keyid < 4; keyid++) { |
91 | if (pmlmepriv->key_mask & BIT(keyid)) { | |
d8ab7e84 JS |
92 | if (keyid == |
93 | psecuritypriv->dot11PrivacyKeyIndex) | |
5e93f352 LF |
94 | result = rtw_set_key23a(padapter, psecuritypriv, keyid, 1); |
95 | else | |
96 | result = rtw_set_key23a(padapter, psecuritypriv, keyid, 0); | |
97 | } | |
98 | } | |
99 | } | |
100 | ||
d8ab7e84 | 101 | DBG_8723A("==> ips_leave23a.....LED(0x%08x)...\n", |
050abc45 | 102 | rtl8723au_read32(padapter, 0x4c)); |
5e93f352 LF |
103 | pwrpriv->bips_processing = false; |
104 | ||
105 | pwrpriv->bkeepfwalive = false; | |
106 | pwrpriv->bpower_saving = false; | |
107 | } | |
108 | ||
109 | up(&pwrpriv->lock); | |
110 | ||
111 | return result; | |
112 | } | |
113 | ||
114 | ||
115 | static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter) | |
116 | { | |
5e93f352 LF |
117 | struct mlme_priv *pmlmepriv = &adapter->mlmepriv; |
118 | struct xmit_priv *pxmit_priv = &adapter->xmitpriv; | |
5e93f352 LF |
119 | |
120 | bool ret = false; | |
121 | ||
c17416ef | 122 | if (time_after_eq(adapter->pwrctrlpriv.ips_deny_time, jiffies)) |
5e93f352 LF |
123 | goto exit; |
124 | ||
98fb8129 JS |
125 | if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || |
126 | check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) || | |
127 | check_fwstate(pmlmepriv, WIFI_AP_STATE) || | |
128 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)){ | |
5e93f352 LF |
129 | goto exit; |
130 | } | |
131 | ||
5e93f352 LF |
132 | if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || |
133 | pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { | |
d8ab7e84 JS |
134 | DBG_8723A_LEVEL(_drv_always_, |
135 | "There are some pkts to transmit\n"); | |
136 | DBG_8723A_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, " | |
137 | "free_xmit_extbuf_cnt: %d\n", | |
138 | pxmit_priv->free_xmitbuf_cnt, | |
139 | pxmit_priv->free_xmit_extbuf_cnt); | |
5e93f352 LF |
140 | goto exit; |
141 | } | |
142 | ||
143 | ret = true; | |
144 | ||
145 | exit: | |
146 | return ret; | |
147 | } | |
148 | ||
149 | void rtw_ps_processor23a(struct rtw_adapter*padapter) | |
150 | { | |
151 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
152 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
153 | enum rt_rf_power_state rfpwrstate; | |
154 | ||
155 | pwrpriv->ps_processing = true; | |
156 | ||
157 | if (pwrpriv->bips_processing == true) | |
158 | goto exit; | |
159 | ||
160 | if (padapter->pwrctrlpriv.bHWPwrPindetect) { | |
161 | rfpwrstate = RfOnOffDetect23a(padapter); | |
d8ab7e84 JS |
162 | DBG_8723A("@@@@- #2 %s ==> rfstate:%s\n", __func__, |
163 | (rfpwrstate == rf_on)?"rf_on":"rf_off"); | |
5e93f352 LF |
164 | |
165 | if (rfpwrstate!= pwrpriv->rf_pwrstate) { | |
166 | if (rfpwrstate == rf_off) { | |
167 | pwrpriv->change_rfpwrstate = rf_off; | |
5e93f352 LF |
168 | padapter->bCardDisableWOHSM = true; |
169 | rtw_hw_suspend23a(padapter); | |
170 | } else { | |
171 | pwrpriv->change_rfpwrstate = rf_on; | |
172 | rtw_hw_resume23a(padapter); | |
173 | } | |
d8ab7e84 JS |
174 | DBG_8723A("current rf_pwrstate(%s)\n", |
175 | (pwrpriv->rf_pwrstate == rf_off) ? | |
176 | "rf_off":"rf_on"); | |
5e93f352 LF |
177 | } |
178 | pwrpriv->pwr_state_check_cnts ++; | |
179 | } | |
180 | ||
181 | if (pwrpriv->ips_mode_req == IPS_NONE) | |
182 | goto exit; | |
183 | ||
184 | if (rtw_pwr_unassociated_idle(padapter) == false) | |
185 | goto exit; | |
186 | ||
d8ab7e84 JS |
187 | if (pwrpriv->rf_pwrstate == rf_on && |
188 | (pwrpriv->pwr_state_check_cnts % 4) == 0) { | |
189 | DBG_8723A("==>%s .fw_state(%x)\n", __func__, | |
190 | get_fwstate(pmlmepriv)); | |
5e93f352 LF |
191 | pwrpriv->change_rfpwrstate = rf_off; |
192 | ips_enter23a(padapter); | |
193 | } | |
194 | exit: | |
195 | rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); | |
196 | pwrpriv->ps_processing = false; | |
197 | return; | |
198 | } | |
199 | ||
200 | static void pwr_state_check_handler(unsigned long data) | |
201 | { | |
202 | struct rtw_adapter *padapter = (struct rtw_adapter *)data; | |
203 | rtw_ps_cmd23a(padapter); | |
204 | } | |
205 | ||
206 | /* | |
207 | * | |
208 | * Parameters | |
d8ab7e84 JS |
209 | * padapter |
210 | * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 | |
5e93f352 LF |
211 | * |
212 | */ | |
213 | void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 pslv) | |
214 | { | |
d8ab7e84 | 215 | u8 rpwm; |
5e93f352 LF |
216 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; |
217 | ||
5e93f352 LF |
218 | pslv = PS_STATE(pslv); |
219 | ||
d8ab7e84 | 220 | if (pwrpriv->btcoex_rfon) { |
5e93f352 LF |
221 | if (pslv < PS_STATE_S4) |
222 | pslv = PS_STATE_S3; | |
223 | } | |
224 | ||
225 | if (pwrpriv->rpwm == pslv) { | |
226 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
d8ab7e84 JS |
227 | ("%s: Already set rpwm[0x%02X], new = 0x%02X!\n", |
228 | __func__, pwrpriv->rpwm, pslv)); | |
5e93f352 LF |
229 | return; |
230 | } | |
231 | ||
d8ab7e84 JS |
232 | if (padapter->bSurpriseRemoved == true || |
233 | padapter->hw_init_completed == false) { | |
5e93f352 | 234 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, |
d8ab7e84 JS |
235 | ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", |
236 | __func__, padapter->bSurpriseRemoved, | |
237 | padapter->hw_init_completed)); | |
5e93f352 LF |
238 | |
239 | pwrpriv->cpwm = PS_STATE_S4; | |
240 | ||
241 | return; | |
242 | } | |
243 | ||
244 | if (padapter->bDriverStopped == true) { | |
245 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
d8ab7e84 JS |
246 | ("%s: change power state(0x%02X) when DriverStopped\n", |
247 | __func__, pslv)); | |
5e93f352 LF |
248 | |
249 | if (pslv < PS_STATE_S2) { | |
250 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, | |
d8ab7e84 JS |
251 | ("%s: Reject to enter PS_STATE(0x%02X) lower " |
252 | "than S2 when DriverStopped!!\n", | |
253 | __func__, pslv)); | |
5e93f352 LF |
254 | return; |
255 | } | |
256 | } | |
257 | ||
258 | rpwm = pslv | pwrpriv->tog; | |
259 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, | |
d8ab7e84 JS |
260 | ("rtw_set_rpwm23a: rpwm = 0x%02x cpwm = 0x%02x\n", |
261 | rpwm, pwrpriv->cpwm)); | |
5e93f352 LF |
262 | |
263 | pwrpriv->rpwm = pslv; | |
264 | ||
9ff3513c | 265 | rtl8723a_set_rpwm(padapter, rpwm); |
5e93f352 LF |
266 | |
267 | pwrpriv->tog += 0x80; | |
268 | pwrpriv->cpwm = pslv; | |
5e93f352 LF |
269 | } |
270 | ||
983ebef5 | 271 | static bool PS_RDY_CHECK(struct rtw_adapter * padapter) |
5e93f352 LF |
272 | { |
273 | unsigned long delta_time; | |
d8ab7e84 | 274 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; |
5e93f352 LF |
275 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
276 | ||
277 | delta_time = jiffies - pwrpriv->DelayLPSLastTimeStamp; | |
278 | ||
279 | if (delta_time < LPS_DELAY_TIME) | |
5e93f352 | 280 | return false; |
5e93f352 | 281 | |
0618dbc6 | 282 | if (!check_fwstate(pmlmepriv, _FW_LINKED) || |
f2f97035 JS |
283 | check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) || |
284 | check_fwstate(pmlmepriv, WIFI_AP_STATE) || | |
285 | check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || | |
286 | check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) | |
5e93f352 | 287 | return false; |
d8ab7e84 | 288 | if (pwrpriv->bInSuspend) |
5e93f352 | 289 | return false; |
d8ab7e84 | 290 | if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && |
9216c517 | 291 | !padapter->securitypriv.binstallGrpkey) { |
5e93f352 LF |
292 | DBG_8723A("Group handshake still in progress !!!\n"); |
293 | return false; | |
294 | } | |
295 | if (!rtw_cfg80211_pwr_mgmt(padapter)) | |
296 | return false; | |
297 | ||
298 | return true; | |
299 | } | |
300 | ||
d8ab7e84 JS |
301 | void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, |
302 | u8 smart_ps, u8 bcn_ant_mode) | |
5e93f352 LF |
303 | { |
304 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
5e93f352 LF |
305 | |
306 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, | |
307 | ("%s: PowerMode =%d Smart_PS =%d\n", | |
308 | __func__, ps_mode, smart_ps)); | |
309 | ||
310 | if (ps_mode > PM_Card_Disable) { | |
d8ab7e84 JS |
311 | RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, |
312 | ("ps_mode:%d error\n", ps_mode)); | |
5e93f352 LF |
313 | return; |
314 | } | |
315 | ||
d8ab7e84 JS |
316 | if (pwrpriv->pwr_mode == ps_mode) { |
317 | if (PS_MODE_ACTIVE == ps_mode) | |
318 | return; | |
5e93f352 | 319 | |
d8ab7e84 JS |
320 | if (pwrpriv->smart_ps == smart_ps && |
321 | pwrpriv->bcn_ant_mode == bcn_ant_mode) | |
5e93f352 | 322 | return; |
5e93f352 LF |
323 | } |
324 | ||
325 | if (ps_mode == PS_MODE_ACTIVE) { | |
98fb8129 | 326 | DBG_8723A("rtw_set_ps_mode23a: Leave 802.11 power save\n"); |
5e93f352 | 327 | |
98fb8129 JS |
328 | pwrpriv->pwr_mode = ps_mode; |
329 | rtw_set_rpwm23a(padapter, PS_STATE_S4); | |
330 | rtl8723a_set_FwPwrMode_cmd(padapter, ps_mode); | |
331 | pwrpriv->bFwCurrentInPSMode = false; | |
327c70c0 | 332 | } else { |
e631bae3 JS |
333 | if (PS_RDY_CHECK(padapter) || |
334 | rtl8723a_BT_using_antenna_1(padapter)) { | |
5e93f352 LF |
335 | DBG_8723A("%s: Enter 802.11 power save\n", __func__); |
336 | ||
337 | pwrpriv->bFwCurrentInPSMode = true; | |
338 | pwrpriv->pwr_mode = ps_mode; | |
339 | pwrpriv->smart_ps = smart_ps; | |
340 | pwrpriv->bcn_ant_mode = bcn_ant_mode; | |
327c70c0 | 341 | rtl8723a_set_FwPwrMode_cmd(padapter, ps_mode); |
5e93f352 | 342 | |
5e93f352 LF |
343 | rtw_set_rpwm23a(padapter, PS_STATE_S2); |
344 | } | |
345 | } | |
5e93f352 LF |
346 | } |
347 | ||
348 | /* | |
349 | * Return: | |
350 | * 0: Leave OK | |
351 | * -1: Timeout | |
352 | * -2: Other error | |
353 | */ | |
354 | s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms) | |
355 | { | |
c17416ef | 356 | unsigned long start_time, end_time; |
5e93f352 LF |
357 | u8 bAwake = false; |
358 | s32 err = 0; | |
359 | ||
c17416ef LF |
360 | start_time = jiffies; |
361 | end_time = start_time + msecs_to_jiffies(delay_ms); | |
362 | ||
5e93f352 LF |
363 | while (1) |
364 | { | |
0cee8101 JS |
365 | bAwake = rtl8723a_get_fwlps_rf_on(padapter); |
366 | if (bAwake == true) | |
5e93f352 LF |
367 | break; |
368 | ||
0cee8101 | 369 | if (padapter->bSurpriseRemoved == true) { |
5e93f352 LF |
370 | err = -2; |
371 | DBG_8723A("%s: device surprise removed!!\n", __func__); | |
372 | break; | |
373 | } | |
374 | ||
c17416ef | 375 | if (time_after(jiffies, end_time)) { |
5e93f352 | 376 | err = -1; |
d8ab7e84 JS |
377 | DBG_8723A("%s: Wait for FW LPS leave more than %u " |
378 | "ms!\n", __func__, delay_ms); | |
5e93f352 LF |
379 | break; |
380 | } | |
381 | udelay(100); | |
382 | } | |
383 | ||
384 | return err; | |
385 | } | |
386 | ||
387 | /* Description: */ | |
388 | /* Enter the leisure power save mode. */ | |
389 | void LPS_Enter23a(struct rtw_adapter *padapter) | |
390 | { | |
d8ab7e84 | 391 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; |
5e93f352 LF |
392 | |
393 | if (!PS_RDY_CHECK(padapter)) | |
394 | return; | |
395 | ||
396 | if (pwrpriv->bLeisurePs) { | |
397 | /* Idle for a while if we connect to AP a while ago. */ | |
398 | if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ | |
399 | if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { | |
400 | pwrpriv->bpower_saving = true; | |
d8ab7e84 JS |
401 | DBG_8723A("%s smart_ps:%d\n", __func__, |
402 | pwrpriv->smart_ps); | |
5e93f352 | 403 | /* For Tenda W311R IOT issue */ |
d8ab7e84 JS |
404 | rtw_set_ps_mode23a(padapter, |
405 | pwrpriv->power_mgnt, | |
406 | pwrpriv->smart_ps, 0); | |
5e93f352 | 407 | } |
d8ab7e84 | 408 | } else |
5e93f352 | 409 | pwrpriv->LpsIdleCount++; |
5e93f352 LF |
410 | } |
411 | } | |
412 | ||
413 | /* Description: */ | |
414 | /* Leave the leisure power save mode. */ | |
415 | void LPS_Leave23a(struct rtw_adapter *padapter) | |
416 | { | |
417 | #define LPS_LEAVE_TIMEOUT_MS 100 | |
418 | ||
d8ab7e84 | 419 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; |
5e93f352 LF |
420 | |
421 | if (pwrpriv->bLeisurePs) { | |
422 | if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { | |
423 | rtw_set_ps_mode23a(padapter, PS_MODE_ACTIVE, 0, 0); | |
424 | ||
425 | if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) | |
d8ab7e84 JS |
426 | LPS_RF_ON_check23a(padapter, |
427 | LPS_LEAVE_TIMEOUT_MS); | |
5e93f352 LF |
428 | } |
429 | } | |
430 | ||
431 | pwrpriv->bpower_saving = false; | |
432 | } | |
433 | ||
434 | /* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */ | |
435 | /* Move code to function by tynli. 2010.03.26. */ | |
436 | void LeaveAllPowerSaveMode23a(struct rtw_adapter *Adapter) | |
437 | { | |
438 | struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; | |
d8ab7e84 | 439 | u8 enqueue = 0; |
5e93f352 LF |
440 | |
441 | /* DBG_8723A("%s.....\n", __func__); */ | |
f2f97035 | 442 | if (check_fwstate(pmlmepriv, _FW_LINKED)) |
5e93f352 | 443 | rtw_lps_ctrl_wk_cmd23a(Adapter, LPS_CTRL_LEAVE, enqueue); |
5e93f352 LF |
444 | } |
445 | ||
446 | void rtw_init_pwrctrl_priv23a(struct rtw_adapter *padapter) | |
447 | { | |
448 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
449 | ||
450 | sema_init(&pwrctrlpriv->lock, 1); | |
451 | pwrctrlpriv->rf_pwrstate = rf_on; | |
452 | pwrctrlpriv->ips_enter23a_cnts = 0; | |
453 | pwrctrlpriv->ips_leave23a_cnts = 0; | |
454 | pwrctrlpriv->bips_processing = false; | |
455 | ||
456 | pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; | |
457 | pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; | |
458 | ||
459 | pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; | |
460 | pwrctrlpriv->pwr_state_check_cnts = 0; | |
5e93f352 LF |
461 | pwrctrlpriv->bInSuspend = false; |
462 | pwrctrlpriv->bkeepfwalive = false; | |
463 | ||
464 | pwrctrlpriv->LpsIdleCount = 0; | |
d8ab7e84 JS |
465 | |
466 | /* PS_MODE_MIN; */ | |
467 | pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt; | |
468 | pwrctrlpriv->bLeisurePs = | |
469 | (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false; | |
5e93f352 LF |
470 | |
471 | pwrctrlpriv->bFwCurrentInPSMode = false; | |
472 | ||
473 | pwrctrlpriv->rpwm = 0; | |
474 | pwrctrlpriv->cpwm = PS_STATE_S4; | |
475 | ||
476 | pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; | |
477 | pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; | |
478 | pwrctrlpriv->bcn_ant_mode = 0; | |
479 | ||
480 | pwrctrlpriv->tog = 0x80; | |
481 | ||
482 | pwrctrlpriv->btcoex_rfon = false; | |
483 | ||
484 | setup_timer(&pwrctrlpriv->pwr_state_check_timer, | |
485 | pwr_state_check_handler, (unsigned long)padapter); | |
5e93f352 LF |
486 | } |
487 | ||
488 | void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter) | |
489 | { | |
490 | } | |
491 | ||
5e93f352 LF |
492 | inline void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms) |
493 | { | |
494 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
c17416ef | 495 | pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ms); |
5e93f352 LF |
496 | } |
497 | ||
498 | /* | |
499 | * rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend | |
500 | * @adapter: pointer to _adapter structure | |
808bcb4e | 501 | * @ips_deffer_ms: the ms will prevent from falling into IPS after wakeup |
5e93f352 LF |
502 | * Return _SUCCESS or _FAIL |
503 | */ | |
504 | ||
505 | int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const char *caller) | |
506 | { | |
507 | struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; | |
508 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
509 | int ret = _SUCCESS; | |
c17416ef LF |
510 | unsigned long start = jiffies; |
511 | unsigned long new_deny_time; | |
512 | ||
513 | new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); | |
5e93f352 | 514 | |
c17416ef LF |
515 | if (time_before(pwrpriv->ips_deny_time, new_deny_time)) |
516 | pwrpriv->ips_deny_time = new_deny_time; | |
5e93f352 LF |
517 | |
518 | if (pwrpriv->ps_processing) { | |
519 | DBG_8723A("%s wait ps_processing...\n", __func__); | |
c17416ef LF |
520 | while (pwrpriv->ps_processing && |
521 | jiffies_to_msecs(jiffies - start) <= 3000) | |
5e93f352 LF |
522 | msleep(10); |
523 | if (pwrpriv->ps_processing) | |
524 | DBG_8723A("%s wait ps_processing timeout\n", __func__); | |
525 | else | |
526 | DBG_8723A("%s wait ps_processing done\n", __func__); | |
527 | } | |
528 | ||
b7c19c27 | 529 | if (rtw_sreset_inprogress(padapter)) { |
5e93f352 | 530 | DBG_8723A("%s wait sreset_inprogress...\n", __func__); |
b7c19c27 | 531 | while (rtw_sreset_inprogress(padapter) && |
c17416ef | 532 | jiffies_to_msecs(jiffies - start) <= 4000) |
5e93f352 | 533 | msleep(10); |
b7c19c27 | 534 | if (rtw_sreset_inprogress(padapter)) |
d8ab7e84 JS |
535 | DBG_8723A("%s wait sreset_inprogress timeout\n", |
536 | __func__); | |
5e93f352 LF |
537 | else |
538 | DBG_8723A("%s wait sreset_inprogress done\n", __func__); | |
539 | } | |
540 | ||
32dfcb1b | 541 | if (pwrpriv->bInSuspend) { |
5e93f352 LF |
542 | DBG_8723A("%s wait bInSuspend...\n", __func__); |
543 | while (pwrpriv->bInSuspend && | |
c17416ef | 544 | (jiffies_to_msecs(jiffies - start) <= 3000)) { |
5e93f352 LF |
545 | msleep(10); |
546 | } | |
547 | if (pwrpriv->bInSuspend) | |
548 | DBG_8723A("%s wait bInSuspend timeout\n", __func__); | |
549 | else | |
550 | DBG_8723A("%s wait bInSuspend done\n", __func__); | |
551 | } | |
552 | ||
553 | /* System suspend is not allowed to wakeup */ | |
32dfcb1b | 554 | if (pwrpriv->bInSuspend) { |
5e93f352 LF |
555 | ret = _FAIL; |
556 | goto exit; | |
557 | } | |
558 | ||
559 | /* I think this should be check in IPS, LPS, autosuspend functions... */ | |
f2f97035 | 560 | if (check_fwstate(pmlmepriv, _FW_LINKED)) { |
5e93f352 LF |
561 | ret = _SUCCESS; |
562 | goto exit; | |
563 | } | |
564 | ||
565 | if (rf_off == pwrpriv->rf_pwrstate) { | |
566 | DBG_8723A("%s call ips_leave23a....\n", __func__); | |
d8ab7e84 | 567 | if (ips_leave23a(padapter)== _FAIL) { |
5e93f352 LF |
568 | DBG_8723A("======> ips_leave23a fail.............\n"); |
569 | ret = _FAIL; | |
570 | goto exit; | |
571 | } | |
572 | } | |
573 | ||
574 | /* TODO: the following checking need to be merged... */ | |
575 | if (padapter->bDriverStopped || !padapter->bup || | |
576 | !padapter->hw_init_completed) { | |
577 | DBG_8723A("%s: bDriverStopped =%d, bup =%d, hw_init_completed " | |
578 | "=%u\n", caller, padapter->bDriverStopped, | |
579 | padapter->bup, padapter->hw_init_completed); | |
9160518e | 580 | ret = _FAIL; |
5e93f352 LF |
581 | goto exit; |
582 | } | |
583 | ||
584 | exit: | |
c17416ef LF |
585 | new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); |
586 | if (time_before(pwrpriv->ips_deny_time, new_deny_time)) | |
587 | pwrpriv->ips_deny_time = new_deny_time; | |
5e93f352 LF |
588 | return ret; |
589 | } | |
590 | ||
591 | int rtw_pm_set_lps23a(struct rtw_adapter *padapter, u8 mode) | |
592 | { | |
d8ab7e84 | 593 | int ret = 0; |
5e93f352 LF |
594 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; |
595 | ||
d8ab7e84 JS |
596 | if (mode < PS_MODE_NUM) { |
597 | if (pwrctrlpriv->power_mgnt != mode) { | |
5e93f352 | 598 | if (PS_MODE_ACTIVE == mode) |
5e93f352 | 599 | LeaveAllPowerSaveMode23a(padapter); |
5e93f352 | 600 | else |
5e93f352 | 601 | pwrctrlpriv->LpsIdleCount = 2; |
5e93f352 | 602 | pwrctrlpriv->power_mgnt = mode; |
d8ab7e84 JS |
603 | pwrctrlpriv->bLeisurePs = |
604 | (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? | |
605 | true:false; | |
5e93f352 | 606 | } |
d8ab7e84 | 607 | } else |
5e93f352 | 608 | ret = -EINVAL; |
5e93f352 LF |
609 | |
610 | return ret; | |
611 | } | |
612 | ||
613 | int rtw_pm_set_ips23a(struct rtw_adapter *padapter, u8 mode) | |
614 | { | |
615 | struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; | |
616 | ||
c742e339 JS |
617 | if (mode != IPS_NORMAL && mode != IPS_LEVEL_2 && mode != IPS_NONE) |
618 | return -EINVAL; | |
619 | ||
620 | pwrctrlpriv->ips_mode_req = mode; | |
621 | if (mode == IPS_NONE) { | |
5e93f352 | 622 | DBG_8723A("%s %s\n", __func__, "IPS_NONE"); |
d8ab7e84 JS |
623 | if (padapter->bSurpriseRemoved == 0 && |
624 | rtw_pwr_wakeup(padapter) == _FAIL) | |
5e93f352 | 625 | return -EFAULT; |
c742e339 | 626 | } |
d8ab7e84 | 627 | |
5e93f352 LF |
628 | return 0; |
629 | } |