158391efdSNathan Chancellor // SPDX-License-Identifier: GPL-2.0
2554c0a3aSHans de Goede /******************************************************************************
3554c0a3aSHans de Goede *
4554c0a3aSHans de Goede * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5554c0a3aSHans de Goede *
6554c0a3aSHans de Goede ******************************************************************************/
7554c0a3aSHans de Goede #include <drv_types.h>
8554c0a3aSHans de Goede #include <rtw_debug.h>
9554c0a3aSHans de Goede #include <hal_data.h>
10554c0a3aSHans de Goede #include <linux/jiffies.h>
11554c0a3aSHans de Goede
12554c0a3aSHans de Goede
_ips_enter(struct adapter * padapter)13554c0a3aSHans de Goede void _ips_enter(struct adapter *padapter)
14554c0a3aSHans de Goede {
15554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
16554c0a3aSHans de Goede
17554c0a3aSHans de Goede pwrpriv->bips_processing = true;
18554c0a3aSHans de Goede
19554c0a3aSHans de Goede /* syn ips_mode with request */
20554c0a3aSHans de Goede pwrpriv->ips_mode = pwrpriv->ips_mode_req;
21554c0a3aSHans de Goede
22554c0a3aSHans de Goede pwrpriv->ips_enter_cnts++;
23554c0a3aSHans de Goede
24554c0a3aSHans de Goede if (rf_off == pwrpriv->change_rfpwrstate) {
25554c0a3aSHans de Goede pwrpriv->bpower_saving = true;
26554c0a3aSHans de Goede
27554c0a3aSHans de Goede if (pwrpriv->ips_mode == IPS_LEVEL_2)
28554c0a3aSHans de Goede pwrpriv->bkeepfwalive = true;
29554c0a3aSHans de Goede
30554c0a3aSHans de Goede rtw_ips_pwr_down(padapter);
31554c0a3aSHans de Goede pwrpriv->rf_pwrstate = rf_off;
32554c0a3aSHans de Goede }
33554c0a3aSHans de Goede pwrpriv->bips_processing = false;
34554c0a3aSHans de Goede
35554c0a3aSHans de Goede }
36554c0a3aSHans de Goede
ips_enter(struct adapter * padapter)37554c0a3aSHans de Goede void ips_enter(struct adapter *padapter)
38554c0a3aSHans de Goede {
39554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
40554c0a3aSHans de Goede
41554c0a3aSHans de Goede
424c1bcb0eSNishka Dasgupta hal_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req);
43554c0a3aSHans de Goede
4407e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
45554c0a3aSHans de Goede _ips_enter(padapter);
4607e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
47554c0a3aSHans de Goede }
48554c0a3aSHans de Goede
_ips_leave(struct adapter * padapter)49554c0a3aSHans de Goede int _ips_leave(struct adapter *padapter)
50554c0a3aSHans de Goede {
51554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
52554c0a3aSHans de Goede int result = _SUCCESS;
53554c0a3aSHans de Goede
54554c0a3aSHans de Goede if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) {
55554c0a3aSHans de Goede pwrpriv->bips_processing = true;
56554c0a3aSHans de Goede pwrpriv->change_rfpwrstate = rf_on;
57554c0a3aSHans de Goede pwrpriv->ips_leave_cnts++;
58554c0a3aSHans de Goede
59554c0a3aSHans de Goede result = rtw_ips_pwr_up(padapter);
60554c0a3aSHans de Goede if (result == _SUCCESS) {
61554c0a3aSHans de Goede pwrpriv->rf_pwrstate = rf_on;
62554c0a3aSHans de Goede }
63554c0a3aSHans de Goede pwrpriv->bips_processing = false;
64554c0a3aSHans de Goede
65554c0a3aSHans de Goede pwrpriv->bkeepfwalive = false;
66554c0a3aSHans de Goede pwrpriv->bpower_saving = false;
67554c0a3aSHans de Goede }
68554c0a3aSHans de Goede
69554c0a3aSHans de Goede return result;
70554c0a3aSHans de Goede }
71554c0a3aSHans de Goede
ips_leave(struct adapter * padapter)72554c0a3aSHans de Goede int ips_leave(struct adapter *padapter)
73554c0a3aSHans de Goede {
74554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
75554c0a3aSHans de Goede int ret;
76554c0a3aSHans de Goede
77554c0a3aSHans de Goede if (!is_primary_adapter(padapter))
78554c0a3aSHans de Goede return _SUCCESS;
79554c0a3aSHans de Goede
8007e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
81554c0a3aSHans de Goede ret = _ips_leave(padapter);
8207e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
83554c0a3aSHans de Goede
84bc21df67SZhansaya Bagdauletkyzy if (ret == _SUCCESS)
854c1bcb0eSNishka Dasgupta hal_btcoex_IpsNotify(padapter, IPS_NONE);
86554c0a3aSHans de Goede
87554c0a3aSHans de Goede return ret;
88554c0a3aSHans de Goede }
89554c0a3aSHans de Goede
rtw_pwr_unassociated_idle(struct adapter * adapter)90554c0a3aSHans de Goede static bool rtw_pwr_unassociated_idle(struct adapter *adapter)
91554c0a3aSHans de Goede {
92554c0a3aSHans de Goede struct adapter *buddy = adapter->pbuddy_adapter;
93554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
94554c0a3aSHans de Goede struct xmit_priv *pxmit_priv = &adapter->xmitpriv;
95554c0a3aSHans de Goede
96554c0a3aSHans de Goede bool ret = false;
97554c0a3aSHans de Goede
98709c8e49SFabio Aiuto if (adapter_to_pwrctl(adapter)->bpower_saving)
99554c0a3aSHans de Goede goto exit;
100554c0a3aSHans de Goede
101709c8e49SFabio Aiuto if (time_before(jiffies, adapter_to_pwrctl(adapter)->ips_deny_time))
102554c0a3aSHans de Goede goto exit;
103554c0a3aSHans de Goede
104554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
105554c0a3aSHans de Goede || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
106554c0a3aSHans de Goede || check_fwstate(pmlmepriv, WIFI_AP_STATE)
107554c0a3aSHans de Goede || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
108554c0a3aSHans de Goede )
109554c0a3aSHans de Goede goto exit;
110554c0a3aSHans de Goede
111554c0a3aSHans de Goede /* consider buddy, if exist */
112554c0a3aSHans de Goede if (buddy) {
113554c0a3aSHans de Goede struct mlme_priv *b_pmlmepriv = &(buddy->mlmepriv);
114554c0a3aSHans de Goede
115554c0a3aSHans de Goede if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
116554c0a3aSHans de Goede || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
117554c0a3aSHans de Goede || check_fwstate(b_pmlmepriv, WIFI_AP_STATE)
118554c0a3aSHans de Goede || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
119554c0a3aSHans de Goede )
120554c0a3aSHans de Goede goto exit;
121554c0a3aSHans de Goede }
122554c0a3aSHans de Goede
123554c0a3aSHans de Goede if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF ||
124554c0a3aSHans de Goede pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) {
125*79df841bSFabio Aiuto netdev_dbg(adapter->pnetdev,
126*79df841bSFabio Aiuto "There are some pkts to transmit\n");
127*79df841bSFabio Aiuto netdev_dbg(adapter->pnetdev,
128*79df841bSFabio Aiuto "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n",
129*79df841bSFabio Aiuto pxmit_priv->free_xmitbuf_cnt,
130*79df841bSFabio Aiuto pxmit_priv->free_xmit_extbuf_cnt);
131554c0a3aSHans de Goede goto exit;
132554c0a3aSHans de Goede }
133554c0a3aSHans de Goede
134554c0a3aSHans de Goede ret = true;
135554c0a3aSHans de Goede
136554c0a3aSHans de Goede exit:
137554c0a3aSHans de Goede return ret;
138554c0a3aSHans de Goede }
139554c0a3aSHans de Goede
140554c0a3aSHans de Goede
141554c0a3aSHans de Goede /*
142554c0a3aSHans de Goede * ATTENTION:
143554c0a3aSHans de Goede *rtw_ps_processor() doesn't handle LPS.
144554c0a3aSHans de Goede */
rtw_ps_processor(struct adapter * padapter)145554c0a3aSHans de Goede void rtw_ps_processor(struct adapter *padapter)
146554c0a3aSHans de Goede {
147554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
148554c0a3aSHans de Goede struct dvobj_priv *psdpriv = padapter->dvobj;
149554c0a3aSHans de Goede struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
150554c0a3aSHans de Goede u32 ps_deny = 0;
151554c0a3aSHans de Goede
15207e3a844SArnd Bergmann mutex_lock(&adapter_to_pwrctl(padapter)->lock);
153554c0a3aSHans de Goede ps_deny = rtw_ps_deny_get(padapter);
15407e3a844SArnd Bergmann mutex_unlock(&adapter_to_pwrctl(padapter)->lock);
155709c8e49SFabio Aiuto if (ps_deny != 0)
156554c0a3aSHans de Goede goto exit;
157554c0a3aSHans de Goede
1582e20a5acSNishka Dasgupta if (pwrpriv->bInSuspend) {/* system suspend or autosuspend */
159554c0a3aSHans de Goede pdbgpriv->dbg_ps_insuspend_cnt++;
160554c0a3aSHans de Goede return;
161554c0a3aSHans de Goede }
162554c0a3aSHans de Goede
163554c0a3aSHans de Goede pwrpriv->ps_processing = true;
164554c0a3aSHans de Goede
165554c0a3aSHans de Goede if (pwrpriv->ips_mode_req == IPS_NONE)
166554c0a3aSHans de Goede goto exit;
167554c0a3aSHans de Goede
16863a9c3edSJeeeun Evans if (!rtw_pwr_unassociated_idle(padapter))
169554c0a3aSHans de Goede goto exit;
170554c0a3aSHans de Goede
171554c0a3aSHans de Goede if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) {
172554c0a3aSHans de Goede pwrpriv->change_rfpwrstate = rf_off;
173554c0a3aSHans de Goede {
174554c0a3aSHans de Goede ips_enter(padapter);
175554c0a3aSHans de Goede }
176554c0a3aSHans de Goede }
177554c0a3aSHans de Goede exit:
178554c0a3aSHans de Goede pwrpriv->ps_processing = false;
179554c0a3aSHans de Goede }
180554c0a3aSHans de Goede
pwr_state_check_handler(struct timer_list * t)181e8b1844aSKees Cook static void pwr_state_check_handler(struct timer_list *t)
182554c0a3aSHans de Goede {
183e8b1844aSKees Cook struct pwrctrl_priv *pwrctrlpriv =
184e8b1844aSKees Cook from_timer(pwrctrlpriv, t, pwr_state_check_timer);
185e8b1844aSKees Cook struct adapter *padapter = pwrctrlpriv->adapter;
186e8b1844aSKees Cook
187554c0a3aSHans de Goede rtw_ps_cmd(padapter);
188554c0a3aSHans de Goede }
189554c0a3aSHans de Goede
traffic_check_for_leave_lps(struct adapter * padapter,u8 tx,u32 tx_packets)190554c0a3aSHans de Goede void traffic_check_for_leave_lps(struct adapter *padapter, u8 tx, u32 tx_packets)
191554c0a3aSHans de Goede {
19240d4aa0fSShreeya Patel static unsigned long start_time;
19340d4aa0fSShreeya Patel static u32 xmit_cnt;
194554c0a3aSHans de Goede u8 bLeaveLPS = false;
195554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
196554c0a3aSHans de Goede
197554c0a3aSHans de Goede
198554c0a3aSHans de Goede
199554c0a3aSHans de Goede if (tx) { /* from tx */
200554c0a3aSHans de Goede xmit_cnt += tx_packets;
201554c0a3aSHans de Goede
202554c0a3aSHans de Goede if (start_time == 0)
203554c0a3aSHans de Goede start_time = jiffies;
204554c0a3aSHans de Goede
205554c0a3aSHans de Goede if (jiffies_to_msecs(jiffies - start_time) > 2000) { /* 2 sec == watch dog timer */
206554c0a3aSHans de Goede if (xmit_cnt > 8) {
2072e20a5acSNishka Dasgupta if (adapter_to_pwrctl(padapter)->bLeisurePs
208554c0a3aSHans de Goede && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
2092e20a5acSNishka Dasgupta && !(hal_btcoex_IsBtControlLps(padapter))) {
210554c0a3aSHans de Goede bLeaveLPS = true;
211554c0a3aSHans de Goede }
212554c0a3aSHans de Goede }
213554c0a3aSHans de Goede
214554c0a3aSHans de Goede start_time = jiffies;
215554c0a3aSHans de Goede xmit_cnt = 0;
216554c0a3aSHans de Goede }
217554c0a3aSHans de Goede
218554c0a3aSHans de Goede } else { /* from rx path */
219554c0a3aSHans de Goede if (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4/*2*/) {
2202e20a5acSNishka Dasgupta if (adapter_to_pwrctl(padapter)->bLeisurePs
221554c0a3aSHans de Goede && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE)
222709c8e49SFabio Aiuto && !(hal_btcoex_IsBtControlLps(padapter)))
223554c0a3aSHans de Goede bLeaveLPS = true;
224554c0a3aSHans de Goede }
225554c0a3aSHans de Goede }
226554c0a3aSHans de Goede
227554c0a3aSHans de Goede if (bLeaveLPS)
228554c0a3aSHans de Goede /* rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1); */
229554c0a3aSHans de Goede rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, tx?0:1);
230554c0a3aSHans de Goede }
231554c0a3aSHans de Goede
232554c0a3aSHans de Goede /*
233554c0a3aSHans de Goede * Description:
234554c0a3aSHans de Goede *This function MUST be called under power lock protect
235554c0a3aSHans de Goede *
236554c0a3aSHans de Goede * Parameters
237554c0a3aSHans de Goede *padapter
238554c0a3aSHans de Goede *pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4
239554c0a3aSHans de Goede *
240554c0a3aSHans de Goede */
rtw_set_rpwm(struct adapter * padapter,u8 pslv)241554c0a3aSHans de Goede void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
242554c0a3aSHans de Goede {
243554c0a3aSHans de Goede u8 rpwm;
244554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
245554c0a3aSHans de Goede u8 cpwm_orig;
246554c0a3aSHans de Goede
247554c0a3aSHans de Goede pslv = PS_STATE(pslv);
248554c0a3aSHans de Goede
24921e161c3SFabio Aiuto if (!pwrpriv->brpwmtimeout) {
2502569996dSFabio Aiuto if (pwrpriv->rpwm == pslv ||
2512569996dSFabio Aiuto (pwrpriv->rpwm >= PS_STATE_S2 && pslv >= PS_STATE_S2))
252554c0a3aSHans de Goede return;
2531c7b5dffSFabio Aiuto
254554c0a3aSHans de Goede }
255554c0a3aSHans de Goede
2562e20a5acSNishka Dasgupta if ((padapter->bSurpriseRemoved) || !(padapter->hw_init_completed)) {
257554c0a3aSHans de Goede pwrpriv->cpwm = PS_STATE_S4;
258554c0a3aSHans de Goede
259554c0a3aSHans de Goede return;
260554c0a3aSHans de Goede }
261554c0a3aSHans de Goede
2622e20a5acSNishka Dasgupta if (padapter->bDriverStopped) {
2631c7b5dffSFabio Aiuto if (pslv < PS_STATE_S2)
264554c0a3aSHans de Goede return;
265554c0a3aSHans de Goede }
266554c0a3aSHans de Goede
267554c0a3aSHans de Goede rpwm = pslv | pwrpriv->tog;
268554c0a3aSHans de Goede /* only when from PS_STATE S0/S1 to S2 and higher needs ACK */
269554c0a3aSHans de Goede if ((pwrpriv->cpwm < PS_STATE_S2) && (pslv >= PS_STATE_S2))
270554c0a3aSHans de Goede rpwm |= PS_ACK;
271554c0a3aSHans de Goede
272554c0a3aSHans de Goede pwrpriv->rpwm = pslv;
273554c0a3aSHans de Goede
274554c0a3aSHans de Goede cpwm_orig = 0;
275554c0a3aSHans de Goede if (rpwm & PS_ACK)
276554c0a3aSHans de Goede rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig);
277554c0a3aSHans de Goede
278554c0a3aSHans de Goede if (rpwm & PS_ACK)
279554c0a3aSHans de Goede _set_timer(&pwrpriv->pwr_rpwm_timer, LPS_RPWM_WAIT_MS);
280554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm));
281554c0a3aSHans de Goede
282554c0a3aSHans de Goede pwrpriv->tog += 0x80;
283554c0a3aSHans de Goede
284554c0a3aSHans de Goede /* No LPS 32K, No Ack */
285554c0a3aSHans de Goede if (rpwm & PS_ACK) {
286554c0a3aSHans de Goede unsigned long start_time;
287554c0a3aSHans de Goede u8 cpwm_now;
288554c0a3aSHans de Goede u8 poll_cnt = 0;
289554c0a3aSHans de Goede
290554c0a3aSHans de Goede start_time = jiffies;
291554c0a3aSHans de Goede
292554c0a3aSHans de Goede /* polling cpwm */
293554c0a3aSHans de Goede do {
294554c0a3aSHans de Goede mdelay(1);
295554c0a3aSHans de Goede poll_cnt++;
296554c0a3aSHans de Goede rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_now);
297554c0a3aSHans de Goede if ((cpwm_orig ^ cpwm_now) & 0x80) {
298554c0a3aSHans de Goede pwrpriv->cpwm = PS_STATE_S4;
299554c0a3aSHans de Goede pwrpriv->cpwm_tog = cpwm_now & PS_TOGGLE;
300554c0a3aSHans de Goede break;
301554c0a3aSHans de Goede }
302554c0a3aSHans de Goede
303554c0a3aSHans de Goede if (jiffies_to_msecs(jiffies - start_time) > LPS_RPWM_WAIT_MS) {
304554c0a3aSHans de Goede _set_timer(&pwrpriv->pwr_rpwm_timer, 1);
305554c0a3aSHans de Goede break;
306554c0a3aSHans de Goede }
307554c0a3aSHans de Goede } while (1);
308554c0a3aSHans de Goede } else
309554c0a3aSHans de Goede pwrpriv->cpwm = pslv;
310554c0a3aSHans de Goede }
311554c0a3aSHans de Goede
PS_RDY_CHECK(struct adapter * padapter)312554c0a3aSHans de Goede static u8 PS_RDY_CHECK(struct adapter *padapter)
313554c0a3aSHans de Goede {
314554c0a3aSHans de Goede unsigned long curr_time, delta_time;
315554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
316554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
317554c0a3aSHans de Goede
3182e20a5acSNishka Dasgupta if (pwrpriv->bInSuspend)
319554c0a3aSHans de Goede return false;
320554c0a3aSHans de Goede
321554c0a3aSHans de Goede curr_time = jiffies;
322554c0a3aSHans de Goede
323554c0a3aSHans de Goede delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp;
324554c0a3aSHans de Goede
325554c0a3aSHans de Goede if (delta_time < LPS_DELAY_TIME)
326554c0a3aSHans de Goede return false;
327554c0a3aSHans de Goede
328554c0a3aSHans de Goede if (check_fwstate(pmlmepriv, WIFI_SITE_MONITOR)
329554c0a3aSHans de Goede || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
330554c0a3aSHans de Goede || check_fwstate(pmlmepriv, WIFI_AP_STATE)
331554c0a3aSHans de Goede || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
332554c0a3aSHans de Goede || rtw_is_scan_deny(padapter)
333554c0a3aSHans de Goede )
334554c0a3aSHans de Goede return false;
335554c0a3aSHans de Goede
336a45759d2SFabio Aiuto if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X &&
337a45759d2SFabio Aiuto !padapter->securitypriv.binstallGrpkey)
338554c0a3aSHans de Goede return false;
339554c0a3aSHans de Goede
340554c0a3aSHans de Goede if (!rtw_cfg80211_pwr_mgmt(padapter))
341554c0a3aSHans de Goede return false;
342554c0a3aSHans de Goede
343554c0a3aSHans de Goede return true;
344554c0a3aSHans de Goede }
345554c0a3aSHans de Goede
rtw_set_ps_mode(struct adapter * padapter,u8 ps_mode,u8 smart_ps,u8 bcn_ant_mode,const char * msg)346554c0a3aSHans de Goede void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode, const char *msg)
347554c0a3aSHans de Goede {
348554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
349554c0a3aSHans de Goede
3501c7b5dffSFabio Aiuto if (ps_mode > PM_Card_Disable)
351554c0a3aSHans de Goede return;
352554c0a3aSHans de Goede
353554c0a3aSHans de Goede if (pwrpriv->pwr_mode == ps_mode)
354bc21df67SZhansaya Bagdauletkyzy if (ps_mode == PS_MODE_ACTIVE)
355554c0a3aSHans de Goede return;
356554c0a3aSHans de Goede
357554c0a3aSHans de Goede
35807e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
359554c0a3aSHans de Goede
360554c0a3aSHans de Goede /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */
361554c0a3aSHans de Goede if (ps_mode == PS_MODE_ACTIVE) {
3622e20a5acSNishka Dasgupta if (!(hal_btcoex_IsBtControlLps(padapter))
3632e20a5acSNishka Dasgupta || (hal_btcoex_IsBtControlLps(padapter)
3642e20a5acSNishka Dasgupta && !(hal_btcoex_IsLpsOn(padapter)))) {
365554c0a3aSHans de Goede pwrpriv->pwr_mode = ps_mode;
366554c0a3aSHans de Goede rtw_set_rpwm(padapter, PS_STATE_S4);
367554c0a3aSHans de Goede
368554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
36990b69822SFabio M. De Francesco pwrpriv->fw_current_in_ps_mode = false;
370554c0a3aSHans de Goede
371a6183154SNishka Dasgupta hal_btcoex_LpsNotify(padapter, ps_mode);
372554c0a3aSHans de Goede }
373554c0a3aSHans de Goede } else {
3748ec06b9fSRoss Schmidt if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE)) ||
3758ec06b9fSRoss Schmidt ((hal_btcoex_IsBtControlLps(padapter)) && (hal_btcoex_IsLpsOn(padapter)))
376554c0a3aSHans de Goede ) {
377554c0a3aSHans de Goede u8 pslv;
378554c0a3aSHans de Goede
379a6183154SNishka Dasgupta hal_btcoex_LpsNotify(padapter, ps_mode);
380554c0a3aSHans de Goede
38190b69822SFabio M. De Francesco pwrpriv->fw_current_in_ps_mode = true;
382554c0a3aSHans de Goede pwrpriv->pwr_mode = ps_mode;
383554c0a3aSHans de Goede pwrpriv->smart_ps = smart_ps;
384554c0a3aSHans de Goede pwrpriv->bcn_ant_mode = bcn_ant_mode;
385554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
386554c0a3aSHans de Goede
387554c0a3aSHans de Goede pslv = PS_STATE_S2;
388554c0a3aSHans de Goede if (pwrpriv->alives == 0)
389554c0a3aSHans de Goede pslv = PS_STATE_S0;
390554c0a3aSHans de Goede
3918ec06b9fSRoss Schmidt if (!(hal_btcoex_IsBtDisabled(padapter)) &&
3928ec06b9fSRoss Schmidt (hal_btcoex_IsBtControlLps(padapter))) {
393554c0a3aSHans de Goede u8 val8;
394554c0a3aSHans de Goede
395ee8e2ce5SNishka Dasgupta val8 = hal_btcoex_LpsVal(padapter);
396554c0a3aSHans de Goede if (val8 & BIT(4))
397554c0a3aSHans de Goede pslv = PS_STATE_S2;
398554c0a3aSHans de Goede }
399554c0a3aSHans de Goede
400554c0a3aSHans de Goede rtw_set_rpwm(padapter, pslv);
401554c0a3aSHans de Goede }
402554c0a3aSHans de Goede }
403554c0a3aSHans de Goede
40407e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
405554c0a3aSHans de Goede }
406554c0a3aSHans de Goede
407554c0a3aSHans de Goede /*
408554c0a3aSHans de Goede * Return:
409554c0a3aSHans de Goede *0: Leave OK
410554c0a3aSHans de Goede *-1: Timeout
411554c0a3aSHans de Goede *-2: Other error
412554c0a3aSHans de Goede */
LPS_RF_ON_check(struct adapter * padapter,u32 delay_ms)413554c0a3aSHans de Goede s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms)
414554c0a3aSHans de Goede {
415554c0a3aSHans de Goede unsigned long start_time;
416554c0a3aSHans de Goede u8 bAwake = false;
417554c0a3aSHans de Goede s32 err = 0;
418554c0a3aSHans de Goede
419554c0a3aSHans de Goede
420554c0a3aSHans de Goede start_time = jiffies;
421554c0a3aSHans de Goede while (1) {
422554c0a3aSHans de Goede rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake);
4232e20a5acSNishka Dasgupta if (bAwake)
424554c0a3aSHans de Goede break;
425554c0a3aSHans de Goede
4262e20a5acSNishka Dasgupta if (padapter->bSurpriseRemoved) {
427554c0a3aSHans de Goede err = -2;
428554c0a3aSHans de Goede break;
429554c0a3aSHans de Goede }
430554c0a3aSHans de Goede
431554c0a3aSHans de Goede if (jiffies_to_msecs(jiffies - start_time) > delay_ms) {
432554c0a3aSHans de Goede err = -1;
433554c0a3aSHans de Goede break;
434554c0a3aSHans de Goede }
435554c0a3aSHans de Goede msleep(1);
436554c0a3aSHans de Goede }
437554c0a3aSHans de Goede
438554c0a3aSHans de Goede return err;
439554c0a3aSHans de Goede }
440554c0a3aSHans de Goede
441554c0a3aSHans de Goede /* */
442554c0a3aSHans de Goede /* Description: */
443554c0a3aSHans de Goede /* Enter the leisure power save mode. */
444554c0a3aSHans de Goede /* */
LPS_Enter(struct adapter * padapter,const char * msg)445554c0a3aSHans de Goede void LPS_Enter(struct adapter *padapter, const char *msg)
446554c0a3aSHans de Goede {
447554c0a3aSHans de Goede struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
448554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj);
449554c0a3aSHans de Goede int n_assoc_iface = 0;
450554c0a3aSHans de Goede char buf[32] = {0};
451554c0a3aSHans de Goede
4522e20a5acSNishka Dasgupta if (hal_btcoex_IsBtControlLps(padapter))
453554c0a3aSHans de Goede return;
454554c0a3aSHans de Goede
455554c0a3aSHans de Goede /* Skip lps enter request if number of assocated adapters is not 1 */
456554c0a3aSHans de Goede if (check_fwstate(&(dvobj->padapters->mlmepriv), WIFI_ASOC_STATE))
457554c0a3aSHans de Goede n_assoc_iface++;
458554c0a3aSHans de Goede if (n_assoc_iface != 1)
459554c0a3aSHans de Goede return;
460554c0a3aSHans de Goede
461554c0a3aSHans de Goede /* Skip lps enter request for adapter not port0 */
462554c0a3aSHans de Goede if (get_iface_type(padapter) != IFACE_PORT0)
463554c0a3aSHans de Goede return;
464554c0a3aSHans de Goede
4652e20a5acSNishka Dasgupta if (!PS_RDY_CHECK(dvobj->padapters))
466554c0a3aSHans de Goede return;
467554c0a3aSHans de Goede
468554c0a3aSHans de Goede if (pwrpriv->bLeisurePs) {
469554c0a3aSHans de Goede /* Idle for a while if we connect to AP a while ago. */
470554c0a3aSHans de Goede if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */
471554c0a3aSHans de Goede if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
47241b25593SCandy Febriyanto scnprintf(buf, sizeof(buf), "WIFI-%s", msg);
473554c0a3aSHans de Goede pwrpriv->bpower_saving = true;
474554c0a3aSHans de Goede rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, padapter->registrypriv.smart_ps, 0, buf);
475554c0a3aSHans de Goede }
476554c0a3aSHans de Goede } else
477554c0a3aSHans de Goede pwrpriv->LpsIdleCount++;
478554c0a3aSHans de Goede }
479554c0a3aSHans de Goede }
480554c0a3aSHans de Goede
481554c0a3aSHans de Goede /* */
482554c0a3aSHans de Goede /* Description: */
483554c0a3aSHans de Goede /* Leave the leisure power save mode. */
484554c0a3aSHans de Goede /* */
LPS_Leave(struct adapter * padapter,const char * msg)485554c0a3aSHans de Goede void LPS_Leave(struct adapter *padapter, const char *msg)
486554c0a3aSHans de Goede {
487554c0a3aSHans de Goede #define LPS_LEAVE_TIMEOUT_MS 100
488554c0a3aSHans de Goede
489554c0a3aSHans de Goede struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
490554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj);
491554c0a3aSHans de Goede char buf[32] = {0};
492554c0a3aSHans de Goede
4932e20a5acSNishka Dasgupta if (hal_btcoex_IsBtControlLps(padapter))
494554c0a3aSHans de Goede return;
495554c0a3aSHans de Goede
496554c0a3aSHans de Goede if (pwrpriv->bLeisurePs) {
497554c0a3aSHans de Goede if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
49841b25593SCandy Febriyanto scnprintf(buf, sizeof(buf), "WIFI-%s", msg);
499554c0a3aSHans de Goede rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, buf);
500554c0a3aSHans de Goede
501554c0a3aSHans de Goede if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
502554c0a3aSHans de Goede LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS);
503554c0a3aSHans de Goede }
504554c0a3aSHans de Goede }
505554c0a3aSHans de Goede
506554c0a3aSHans de Goede pwrpriv->bpower_saving = false;
507554c0a3aSHans de Goede }
508554c0a3aSHans de Goede
LeaveAllPowerSaveModeDirect(struct adapter * Adapter)509554c0a3aSHans de Goede void LeaveAllPowerSaveModeDirect(struct adapter *Adapter)
510554c0a3aSHans de Goede {
511554c0a3aSHans de Goede struct adapter *pri_padapter = GET_PRIMARY_ADAPTER(Adapter);
512554c0a3aSHans de Goede struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
513554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter);
514554c0a3aSHans de Goede
515709c8e49SFabio Aiuto if (Adapter->bSurpriseRemoved)
516554c0a3aSHans de Goede return;
517554c0a3aSHans de Goede
5182e20a5acSNishka Dasgupta if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */
519554c0a3aSHans de Goede
520709c8e49SFabio Aiuto if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
521554c0a3aSHans de Goede return;
522554c0a3aSHans de Goede
52307e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
524554c0a3aSHans de Goede
525554c0a3aSHans de Goede rtw_set_rpwm(Adapter, PS_STATE_S4);
526554c0a3aSHans de Goede
52707e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
528554c0a3aSHans de Goede
529554c0a3aSHans de Goede rtw_lps_ctrl_wk_cmd(pri_padapter, LPS_CTRL_LEAVE, 0);
530554c0a3aSHans de Goede } else {
531554c0a3aSHans de Goede if (pwrpriv->rf_pwrstate == rf_off)
53221e161c3SFabio Aiuto ips_leave(pri_padapter);
533554c0a3aSHans de Goede }
534554c0a3aSHans de Goede }
535554c0a3aSHans de Goede
536554c0a3aSHans de Goede /* */
537554c0a3aSHans de Goede /* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */
538554c0a3aSHans de Goede /* Move code to function by tynli. 2010.03.26. */
539554c0a3aSHans de Goede /* */
LeaveAllPowerSaveMode(struct adapter * Adapter)540554c0a3aSHans de Goede void LeaveAllPowerSaveMode(struct adapter *Adapter)
541554c0a3aSHans de Goede {
542554c0a3aSHans de Goede struct dvobj_priv *dvobj = adapter_to_dvobj(Adapter);
543554c0a3aSHans de Goede u8 enqueue = 0;
544554c0a3aSHans de Goede int n_assoc_iface = 0;
545554c0a3aSHans de Goede
546709c8e49SFabio Aiuto if (!Adapter->bup)
547554c0a3aSHans de Goede return;
548554c0a3aSHans de Goede
549709c8e49SFabio Aiuto if (Adapter->bSurpriseRemoved)
550554c0a3aSHans de Goede return;
551554c0a3aSHans de Goede
552554c0a3aSHans de Goede if (check_fwstate(&(dvobj->padapters->mlmepriv), WIFI_ASOC_STATE))
553554c0a3aSHans de Goede n_assoc_iface++;
554554c0a3aSHans de Goede
555554c0a3aSHans de Goede if (n_assoc_iface) { /* connect */
556554c0a3aSHans de Goede enqueue = 1;
557554c0a3aSHans de Goede
558554c0a3aSHans de Goede rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue);
559554c0a3aSHans de Goede
560554c0a3aSHans de Goede LPS_Leave_check(Adapter);
561554c0a3aSHans de Goede } else {
562554c0a3aSHans de Goede if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) {
56321e161c3SFabio Aiuto ips_leave(Adapter);
564554c0a3aSHans de Goede }
565554c0a3aSHans de Goede }
566554c0a3aSHans de Goede }
567554c0a3aSHans de Goede
LPS_Leave_check(struct adapter * padapter)5685641eeecSRoss Schmidt void LPS_Leave_check(struct adapter *padapter)
569554c0a3aSHans de Goede {
570554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv;
571554c0a3aSHans de Goede unsigned long start_time;
572554c0a3aSHans de Goede u8 bReady;
573554c0a3aSHans de Goede
574554c0a3aSHans de Goede pwrpriv = adapter_to_pwrctl(padapter);
575554c0a3aSHans de Goede
576554c0a3aSHans de Goede bReady = false;
577554c0a3aSHans de Goede start_time = jiffies;
578554c0a3aSHans de Goede
579049b5e2aSThomas Avery cond_resched();
580554c0a3aSHans de Goede
581554c0a3aSHans de Goede while (1) {
58207e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
583554c0a3aSHans de Goede
5848ec06b9fSRoss Schmidt if (padapter->bSurpriseRemoved ||
5858ec06b9fSRoss Schmidt !(padapter->hw_init_completed) ||
5868ec06b9fSRoss Schmidt (pwrpriv->pwr_mode == PS_MODE_ACTIVE))
587554c0a3aSHans de Goede bReady = true;
588554c0a3aSHans de Goede
58907e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
590554c0a3aSHans de Goede
5912e20a5acSNishka Dasgupta if (bReady)
592554c0a3aSHans de Goede break;
593554c0a3aSHans de Goede
594709c8e49SFabio Aiuto if (jiffies_to_msecs(jiffies - start_time) > 100)
595554c0a3aSHans de Goede break;
596709c8e49SFabio Aiuto
597554c0a3aSHans de Goede msleep(1);
598554c0a3aSHans de Goede }
599554c0a3aSHans de Goede }
600554c0a3aSHans de Goede
601554c0a3aSHans de Goede /*
602554c0a3aSHans de Goede * Caller:ISR handler...
603554c0a3aSHans de Goede *
604554c0a3aSHans de Goede * This will be called when CPWM interrupt is up.
605554c0a3aSHans de Goede *
606554c0a3aSHans de Goede * using to update cpwn of drv; and drv willl make a decision to up or down pwr level
607554c0a3aSHans de Goede */
cpwm_int_hdl(struct adapter * padapter,struct reportpwrstate_parm * preportpwrstate)6085641eeecSRoss Schmidt void cpwm_int_hdl(struct adapter *padapter, struct reportpwrstate_parm *preportpwrstate)
609554c0a3aSHans de Goede {
610554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv;
611554c0a3aSHans de Goede
612554c0a3aSHans de Goede pwrpriv = adapter_to_pwrctl(padapter);
613554c0a3aSHans de Goede
61407e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
615554c0a3aSHans de Goede
616709c8e49SFabio Aiuto if (pwrpriv->rpwm < PS_STATE_S2)
617554c0a3aSHans de Goede goto exit;
618554c0a3aSHans de Goede
619554c0a3aSHans de Goede pwrpriv->cpwm = PS_STATE(preportpwrstate->state);
620554c0a3aSHans de Goede pwrpriv->cpwm_tog = preportpwrstate->state & PS_TOGGLE;
621554c0a3aSHans de Goede
622554c0a3aSHans de Goede if (pwrpriv->cpwm >= PS_STATE_S2) {
623554c0a3aSHans de Goede if (pwrpriv->alives & CMD_ALIVE)
62409a8ea34SArnd Bergmann complete(&padapter->cmdpriv.cmd_queue_comp);
625554c0a3aSHans de Goede
626554c0a3aSHans de Goede if (pwrpriv->alives & XMIT_ALIVE)
62709a8ea34SArnd Bergmann complete(&padapter->xmitpriv.xmit_comp);
628554c0a3aSHans de Goede }
629554c0a3aSHans de Goede
630554c0a3aSHans de Goede exit:
63107e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
63207e3a844SArnd Bergmann
633554c0a3aSHans de Goede }
634554c0a3aSHans de Goede
cpwm_event_callback(struct work_struct * work)635554c0a3aSHans de Goede static void cpwm_event_callback(struct work_struct *work)
636554c0a3aSHans de Goede {
637554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, cpwm_event);
638554c0a3aSHans de Goede struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv);
639554c0a3aSHans de Goede struct adapter *adapter = dvobj->if1;
640554c0a3aSHans de Goede struct reportpwrstate_parm report;
641554c0a3aSHans de Goede
642554c0a3aSHans de Goede report.state = PS_STATE_S2;
643554c0a3aSHans de Goede cpwm_int_hdl(adapter, &report);
644554c0a3aSHans de Goede }
645554c0a3aSHans de Goede
rpwmtimeout_workitem_callback(struct work_struct * work)646554c0a3aSHans de Goede static void rpwmtimeout_workitem_callback(struct work_struct *work)
647554c0a3aSHans de Goede {
648554c0a3aSHans de Goede struct adapter *padapter;
649554c0a3aSHans de Goede struct dvobj_priv *dvobj;
650554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv;
651554c0a3aSHans de Goede
652554c0a3aSHans de Goede
653554c0a3aSHans de Goede pwrpriv = container_of(work, struct pwrctrl_priv, rpwmtimeoutwi);
654554c0a3aSHans de Goede dvobj = pwrctl_to_dvobj(pwrpriv);
655554c0a3aSHans de Goede padapter = dvobj->if1;
656554c0a3aSHans de Goede
65707e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
658709c8e49SFabio Aiuto if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2))
659554c0a3aSHans de Goede goto exit;
660709c8e49SFabio Aiuto
66107e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
662554c0a3aSHans de Goede
663554c0a3aSHans de Goede if (rtw_read8(padapter, 0x100) != 0xEA) {
664554c0a3aSHans de Goede struct reportpwrstate_parm report;
665554c0a3aSHans de Goede
666554c0a3aSHans de Goede report.state = PS_STATE_S2;
667554c0a3aSHans de Goede cpwm_int_hdl(padapter, &report);
668554c0a3aSHans de Goede
669554c0a3aSHans de Goede return;
670554c0a3aSHans de Goede }
671554c0a3aSHans de Goede
67207e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
673554c0a3aSHans de Goede
674709c8e49SFabio Aiuto if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2))
675554c0a3aSHans de Goede goto exit;
676709c8e49SFabio Aiuto
677554c0a3aSHans de Goede pwrpriv->brpwmtimeout = true;
678554c0a3aSHans de Goede rtw_set_rpwm(padapter, pwrpriv->rpwm);
679554c0a3aSHans de Goede pwrpriv->brpwmtimeout = false;
680554c0a3aSHans de Goede
681554c0a3aSHans de Goede exit:
68207e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
683554c0a3aSHans de Goede }
684554c0a3aSHans de Goede
685554c0a3aSHans de Goede /*
686554c0a3aSHans de Goede * This function is a timer handler, can't do any IO in it.
687554c0a3aSHans de Goede */
pwr_rpwm_timeout_handler(struct timer_list * t)688e8b1844aSKees Cook static void pwr_rpwm_timeout_handler(struct timer_list *t)
689554c0a3aSHans de Goede {
690e8b1844aSKees Cook struct pwrctrl_priv *pwrpriv = from_timer(pwrpriv, t, pwr_rpwm_timer);
691554c0a3aSHans de Goede
692709c8e49SFabio Aiuto if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2))
693554c0a3aSHans de Goede return;
694554c0a3aSHans de Goede
695554c0a3aSHans de Goede _set_workitem(&pwrpriv->rpwmtimeoutwi);
696554c0a3aSHans de Goede }
697554c0a3aSHans de Goede
register_task_alive(struct pwrctrl_priv * pwrctrl,u32 tag)6984a397521SRasmus Villemoes static inline void register_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
699554c0a3aSHans de Goede {
700554c0a3aSHans de Goede pwrctrl->alives |= tag;
701554c0a3aSHans de Goede }
702554c0a3aSHans de Goede
unregister_task_alive(struct pwrctrl_priv * pwrctrl,u32 tag)7034a397521SRasmus Villemoes static inline void unregister_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag)
704554c0a3aSHans de Goede {
705554c0a3aSHans de Goede pwrctrl->alives &= ~tag;
706554c0a3aSHans de Goede }
707554c0a3aSHans de Goede
708554c0a3aSHans de Goede
709554c0a3aSHans de Goede /*
710554c0a3aSHans de Goede * Description:
711554c0a3aSHans de Goede *Check if the fw_pwrstate is okay for I/O.
712554c0a3aSHans de Goede *If not (cpwm is less than S2), then the sub-routine
713554c0a3aSHans de Goede *will raise the cpwm to be greater than or equal to S2.
714554c0a3aSHans de Goede *
715554c0a3aSHans de Goede *Calling Context: Passive
716554c0a3aSHans de Goede *
717554c0a3aSHans de Goede *Constraint:
718554c0a3aSHans de Goede * 1. this function will request pwrctrl->lock
719554c0a3aSHans de Goede *
720554c0a3aSHans de Goede * Return Value:
721554c0a3aSHans de Goede *_SUCCESS hardware is ready for I/O
722554c0a3aSHans de Goede *_FAIL can't I/O right now
723554c0a3aSHans de Goede */
rtw_register_task_alive(struct adapter * padapter,u32 task)724554c0a3aSHans de Goede s32 rtw_register_task_alive(struct adapter *padapter, u32 task)
725554c0a3aSHans de Goede {
726554c0a3aSHans de Goede s32 res;
727554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrl;
728554c0a3aSHans de Goede u8 pslv;
729554c0a3aSHans de Goede
730554c0a3aSHans de Goede res = _SUCCESS;
731554c0a3aSHans de Goede pwrctrl = adapter_to_pwrctl(padapter);
732554c0a3aSHans de Goede pslv = PS_STATE_S2;
733554c0a3aSHans de Goede
73407e3a844SArnd Bergmann mutex_lock(&pwrctrl->lock);
735554c0a3aSHans de Goede
736554c0a3aSHans de Goede register_task_alive(pwrctrl, task);
737554c0a3aSHans de Goede
73890b69822SFabio M. De Francesco if (pwrctrl->fw_current_in_ps_mode) {
739554c0a3aSHans de Goede if (pwrctrl->cpwm < pslv) {
740554c0a3aSHans de Goede if (pwrctrl->cpwm < PS_STATE_S2)
741554c0a3aSHans de Goede res = _FAIL;
742554c0a3aSHans de Goede if (pwrctrl->rpwm < pslv)
743554c0a3aSHans de Goede rtw_set_rpwm(padapter, pslv);
744554c0a3aSHans de Goede }
745554c0a3aSHans de Goede }
746554c0a3aSHans de Goede
74707e3a844SArnd Bergmann mutex_unlock(&pwrctrl->lock);
748554c0a3aSHans de Goede
749bc21df67SZhansaya Bagdauletkyzy if (res == _FAIL)
750554c0a3aSHans de Goede if (pwrctrl->cpwm >= PS_STATE_S2)
751554c0a3aSHans de Goede res = _SUCCESS;
752554c0a3aSHans de Goede
753554c0a3aSHans de Goede return res;
754554c0a3aSHans de Goede }
755554c0a3aSHans de Goede
756554c0a3aSHans de Goede /*
757554c0a3aSHans de Goede * Description:
758554c0a3aSHans de Goede *If task is done, call this func. to power down firmware again.
759554c0a3aSHans de Goede *
760554c0a3aSHans de Goede *Constraint:
761554c0a3aSHans de Goede * 1. this function will request pwrctrl->lock
762554c0a3aSHans de Goede *
763554c0a3aSHans de Goede * Return Value:
764554c0a3aSHans de Goede *none
765554c0a3aSHans de Goede */
rtw_unregister_task_alive(struct adapter * padapter,u32 task)766554c0a3aSHans de Goede void rtw_unregister_task_alive(struct adapter *padapter, u32 task)
767554c0a3aSHans de Goede {
768554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrl;
769554c0a3aSHans de Goede u8 pslv;
770554c0a3aSHans de Goede
771554c0a3aSHans de Goede pwrctrl = adapter_to_pwrctl(padapter);
772554c0a3aSHans de Goede pslv = PS_STATE_S0;
773554c0a3aSHans de Goede
7748ec06b9fSRoss Schmidt if (!(hal_btcoex_IsBtDisabled(padapter)) && hal_btcoex_IsBtControlLps(padapter)) {
775554c0a3aSHans de Goede u8 val8;
776554c0a3aSHans de Goede
777ee8e2ce5SNishka Dasgupta val8 = hal_btcoex_LpsVal(padapter);
778554c0a3aSHans de Goede if (val8 & BIT(4))
779554c0a3aSHans de Goede pslv = PS_STATE_S2;
780554c0a3aSHans de Goede }
781554c0a3aSHans de Goede
78207e3a844SArnd Bergmann mutex_lock(&pwrctrl->lock);
783554c0a3aSHans de Goede
784554c0a3aSHans de Goede unregister_task_alive(pwrctrl, task);
785554c0a3aSHans de Goede
78690b69822SFabio M. De Francesco if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->fw_current_in_ps_mode) {
787554c0a3aSHans de Goede if (pwrctrl->cpwm > pslv)
788554c0a3aSHans de Goede if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0))
789554c0a3aSHans de Goede rtw_set_rpwm(padapter, pslv);
790554c0a3aSHans de Goede
791554c0a3aSHans de Goede }
792554c0a3aSHans de Goede
79307e3a844SArnd Bergmann mutex_unlock(&pwrctrl->lock);
794554c0a3aSHans de Goede }
795554c0a3aSHans de Goede
796554c0a3aSHans de Goede /*
797554c0a3aSHans de Goede * Caller: rtw_xmit_thread
798554c0a3aSHans de Goede *
799554c0a3aSHans de Goede * Check if the fw_pwrstate is okay for xmit.
800554c0a3aSHans de Goede * If not (cpwm is less than S3), then the sub-routine
801554c0a3aSHans de Goede * will raise the cpwm to be greater than or equal to S3.
802554c0a3aSHans de Goede *
803554c0a3aSHans de Goede * Calling Context: Passive
804554c0a3aSHans de Goede *
805554c0a3aSHans de Goede * Return Value:
806554c0a3aSHans de Goede * _SUCCESS rtw_xmit_thread can write fifo/txcmd afterwards.
807554c0a3aSHans de Goede * _FAIL rtw_xmit_thread can not do anything.
808554c0a3aSHans de Goede */
rtw_register_tx_alive(struct adapter * padapter)809554c0a3aSHans de Goede s32 rtw_register_tx_alive(struct adapter *padapter)
810554c0a3aSHans de Goede {
811554c0a3aSHans de Goede s32 res;
812554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrl;
813554c0a3aSHans de Goede u8 pslv;
814554c0a3aSHans de Goede
815554c0a3aSHans de Goede res = _SUCCESS;
816554c0a3aSHans de Goede pwrctrl = adapter_to_pwrctl(padapter);
817554c0a3aSHans de Goede pslv = PS_STATE_S2;
818554c0a3aSHans de Goede
81907e3a844SArnd Bergmann mutex_lock(&pwrctrl->lock);
820554c0a3aSHans de Goede
821554c0a3aSHans de Goede register_task_alive(pwrctrl, XMIT_ALIVE);
822554c0a3aSHans de Goede
82390b69822SFabio M. De Francesco if (pwrctrl->fw_current_in_ps_mode) {
824554c0a3aSHans de Goede if (pwrctrl->cpwm < pslv) {
825554c0a3aSHans de Goede if (pwrctrl->cpwm < PS_STATE_S2)
826554c0a3aSHans de Goede res = _FAIL;
827554c0a3aSHans de Goede if (pwrctrl->rpwm < pslv)
828554c0a3aSHans de Goede rtw_set_rpwm(padapter, pslv);
829554c0a3aSHans de Goede }
830554c0a3aSHans de Goede }
831554c0a3aSHans de Goede
83207e3a844SArnd Bergmann mutex_unlock(&pwrctrl->lock);
833554c0a3aSHans de Goede
834bc21df67SZhansaya Bagdauletkyzy if (res == _FAIL)
835554c0a3aSHans de Goede if (pwrctrl->cpwm >= PS_STATE_S2)
836554c0a3aSHans de Goede res = _SUCCESS;
837554c0a3aSHans de Goede
838554c0a3aSHans de Goede return res;
839554c0a3aSHans de Goede }
840554c0a3aSHans de Goede
841554c0a3aSHans de Goede /*
842554c0a3aSHans de Goede * Caller: rtw_cmd_thread
843554c0a3aSHans de Goede *
844554c0a3aSHans de Goede * Check if the fw_pwrstate is okay for issuing cmd.
845554c0a3aSHans de Goede * If not (cpwm should be is less than S2), then the sub-routine
846554c0a3aSHans de Goede * will raise the cpwm to be greater than or equal to S2.
847554c0a3aSHans de Goede *
848554c0a3aSHans de Goede * Calling Context: Passive
849554c0a3aSHans de Goede *
850554c0a3aSHans de Goede * Return Value:
851554c0a3aSHans de Goede *_SUCCESS rtw_cmd_thread can issue cmds to firmware afterwards.
852554c0a3aSHans de Goede *_FAIL rtw_cmd_thread can not do anything.
853554c0a3aSHans de Goede */
rtw_register_cmd_alive(struct adapter * padapter)854554c0a3aSHans de Goede s32 rtw_register_cmd_alive(struct adapter *padapter)
855554c0a3aSHans de Goede {
856554c0a3aSHans de Goede s32 res;
857554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrl;
858554c0a3aSHans de Goede u8 pslv;
859554c0a3aSHans de Goede
860554c0a3aSHans de Goede res = _SUCCESS;
861554c0a3aSHans de Goede pwrctrl = adapter_to_pwrctl(padapter);
862554c0a3aSHans de Goede pslv = PS_STATE_S2;
863554c0a3aSHans de Goede
86407e3a844SArnd Bergmann mutex_lock(&pwrctrl->lock);
865554c0a3aSHans de Goede
866554c0a3aSHans de Goede register_task_alive(pwrctrl, CMD_ALIVE);
867554c0a3aSHans de Goede
86890b69822SFabio M. De Francesco if (pwrctrl->fw_current_in_ps_mode) {
869554c0a3aSHans de Goede if (pwrctrl->cpwm < pslv) {
870554c0a3aSHans de Goede if (pwrctrl->cpwm < PS_STATE_S2)
871554c0a3aSHans de Goede res = _FAIL;
872554c0a3aSHans de Goede if (pwrctrl->rpwm < pslv)
873554c0a3aSHans de Goede rtw_set_rpwm(padapter, pslv);
874554c0a3aSHans de Goede }
875554c0a3aSHans de Goede }
876554c0a3aSHans de Goede
87707e3a844SArnd Bergmann mutex_unlock(&pwrctrl->lock);
878554c0a3aSHans de Goede
879bc21df67SZhansaya Bagdauletkyzy if (res == _FAIL)
880554c0a3aSHans de Goede if (pwrctrl->cpwm >= PS_STATE_S2)
881554c0a3aSHans de Goede res = _SUCCESS;
882554c0a3aSHans de Goede
883554c0a3aSHans de Goede return res;
884554c0a3aSHans de Goede }
885554c0a3aSHans de Goede
886554c0a3aSHans de Goede /*
887554c0a3aSHans de Goede * Caller: ISR
888554c0a3aSHans de Goede *
889554c0a3aSHans de Goede * If ISR's txdone,
890554c0a3aSHans de Goede * No more pkts for TX,
891554c0a3aSHans de Goede * Then driver shall call this fun. to power down firmware again.
892554c0a3aSHans de Goede */
rtw_unregister_tx_alive(struct adapter * padapter)893554c0a3aSHans de Goede void rtw_unregister_tx_alive(struct adapter *padapter)
894554c0a3aSHans de Goede {
895554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrl;
896554c0a3aSHans de Goede u8 pslv;
897554c0a3aSHans de Goede
898554c0a3aSHans de Goede pwrctrl = adapter_to_pwrctl(padapter);
899554c0a3aSHans de Goede pslv = PS_STATE_S0;
900554c0a3aSHans de Goede
9018ec06b9fSRoss Schmidt if (!(hal_btcoex_IsBtDisabled(padapter)) && hal_btcoex_IsBtControlLps(padapter)) {
902554c0a3aSHans de Goede u8 val8;
903554c0a3aSHans de Goede
904ee8e2ce5SNishka Dasgupta val8 = hal_btcoex_LpsVal(padapter);
905554c0a3aSHans de Goede if (val8 & BIT(4))
906554c0a3aSHans de Goede pslv = PS_STATE_S2;
907554c0a3aSHans de Goede }
908554c0a3aSHans de Goede
90907e3a844SArnd Bergmann mutex_lock(&pwrctrl->lock);
910554c0a3aSHans de Goede
911554c0a3aSHans de Goede unregister_task_alive(pwrctrl, XMIT_ALIVE);
912554c0a3aSHans de Goede
91390b69822SFabio M. De Francesco if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->fw_current_in_ps_mode) {
914554c0a3aSHans de Goede if (pwrctrl->cpwm > pslv)
915554c0a3aSHans de Goede if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0))
916554c0a3aSHans de Goede rtw_set_rpwm(padapter, pslv);
917554c0a3aSHans de Goede }
918554c0a3aSHans de Goede
91907e3a844SArnd Bergmann mutex_unlock(&pwrctrl->lock);
920554c0a3aSHans de Goede }
921554c0a3aSHans de Goede
922554c0a3aSHans de Goede /*
923554c0a3aSHans de Goede * Caller: ISR
924554c0a3aSHans de Goede *
925554c0a3aSHans de Goede * If all commands have been done,
926554c0a3aSHans de Goede * and no more command to do,
927554c0a3aSHans de Goede * then driver shall call this fun. to power down firmware again.
928554c0a3aSHans de Goede */
rtw_unregister_cmd_alive(struct adapter * padapter)929554c0a3aSHans de Goede void rtw_unregister_cmd_alive(struct adapter *padapter)
930554c0a3aSHans de Goede {
931554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrl;
932554c0a3aSHans de Goede u8 pslv;
933554c0a3aSHans de Goede
934554c0a3aSHans de Goede pwrctrl = adapter_to_pwrctl(padapter);
935554c0a3aSHans de Goede pslv = PS_STATE_S0;
936554c0a3aSHans de Goede
9378ec06b9fSRoss Schmidt if (!(hal_btcoex_IsBtDisabled(padapter)) && hal_btcoex_IsBtControlLps(padapter)) {
938554c0a3aSHans de Goede u8 val8;
939554c0a3aSHans de Goede
940ee8e2ce5SNishka Dasgupta val8 = hal_btcoex_LpsVal(padapter);
941554c0a3aSHans de Goede if (val8 & BIT(4))
942554c0a3aSHans de Goede pslv = PS_STATE_S2;
943554c0a3aSHans de Goede }
944554c0a3aSHans de Goede
94507e3a844SArnd Bergmann mutex_lock(&pwrctrl->lock);
946554c0a3aSHans de Goede
947554c0a3aSHans de Goede unregister_task_alive(pwrctrl, CMD_ALIVE);
948554c0a3aSHans de Goede
94990b69822SFabio M. De Francesco if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->fw_current_in_ps_mode) {
950554c0a3aSHans de Goede if (pwrctrl->cpwm > pslv) {
951554c0a3aSHans de Goede if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0))
952554c0a3aSHans de Goede rtw_set_rpwm(padapter, pslv);
953554c0a3aSHans de Goede }
954554c0a3aSHans de Goede }
955554c0a3aSHans de Goede
95607e3a844SArnd Bergmann mutex_unlock(&pwrctrl->lock);
957554c0a3aSHans de Goede }
958554c0a3aSHans de Goede
rtw_init_pwrctrl_priv(struct adapter * padapter)959554c0a3aSHans de Goede void rtw_init_pwrctrl_priv(struct adapter *padapter)
960554c0a3aSHans de Goede {
961554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
962554c0a3aSHans de Goede
96307e3a844SArnd Bergmann mutex_init(&pwrctrlpriv->lock);
964554c0a3aSHans de Goede pwrctrlpriv->rf_pwrstate = rf_on;
965554c0a3aSHans de Goede pwrctrlpriv->ips_enter_cnts = 0;
966554c0a3aSHans de Goede pwrctrlpriv->ips_leave_cnts = 0;
967554c0a3aSHans de Goede pwrctrlpriv->bips_processing = false;
968554c0a3aSHans de Goede
969554c0a3aSHans de Goede pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode;
970554c0a3aSHans de Goede pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode;
971554c0a3aSHans de Goede
972554c0a3aSHans de Goede pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL;
973554c0a3aSHans de Goede pwrctrlpriv->pwr_state_check_cnts = 0;
974554c0a3aSHans de Goede pwrctrlpriv->bInternalAutoSuspend = false;
975554c0a3aSHans de Goede pwrctrlpriv->bInSuspend = false;
976554c0a3aSHans de Goede pwrctrlpriv->bkeepfwalive = false;
977554c0a3aSHans de Goede
978554c0a3aSHans de Goede pwrctrlpriv->LpsIdleCount = 0;
979554c0a3aSHans de Goede pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */
98095b3b423SAastha Gupta pwrctrlpriv->bLeisurePs = pwrctrlpriv->power_mgnt != PS_MODE_ACTIVE;
981554c0a3aSHans de Goede
98290b69822SFabio M. De Francesco pwrctrlpriv->fw_current_in_ps_mode = false;
983554c0a3aSHans de Goede
984554c0a3aSHans de Goede pwrctrlpriv->rpwm = 0;
985554c0a3aSHans de Goede pwrctrlpriv->cpwm = PS_STATE_S4;
986554c0a3aSHans de Goede
987554c0a3aSHans de Goede pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
988554c0a3aSHans de Goede pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps;
989554c0a3aSHans de Goede pwrctrlpriv->bcn_ant_mode = 0;
990554c0a3aSHans de Goede pwrctrlpriv->dtim = 0;
991554c0a3aSHans de Goede
992554c0a3aSHans de Goede pwrctrlpriv->tog = 0x80;
993554c0a3aSHans de Goede
994554c0a3aSHans de Goede rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&pwrctrlpriv->rpwm));
995554c0a3aSHans de Goede
996554c0a3aSHans de Goede _init_workitem(&pwrctrlpriv->cpwm_event, cpwm_event_callback, NULL);
997554c0a3aSHans de Goede
998554c0a3aSHans de Goede pwrctrlpriv->brpwmtimeout = false;
999e8b1844aSKees Cook pwrctrlpriv->adapter = padapter;
1000554c0a3aSHans de Goede _init_workitem(&pwrctrlpriv->rpwmtimeoutwi, rpwmtimeout_workitem_callback, NULL);
1001e8b1844aSKees Cook timer_setup(&pwrctrlpriv->pwr_rpwm_timer, pwr_rpwm_timeout_handler, 0);
1002e8b1844aSKees Cook timer_setup(&pwrctrlpriv->pwr_state_check_timer,
1003e8b1844aSKees Cook pwr_state_check_handler, 0);
1004554c0a3aSHans de Goede
1005554c0a3aSHans de Goede pwrctrlpriv->wowlan_mode = false;
1006554c0a3aSHans de Goede pwrctrlpriv->wowlan_ap_mode = false;
1007554c0a3aSHans de Goede }
1008554c0a3aSHans de Goede
1009554c0a3aSHans de Goede
rtw_free_pwrctrl_priv(struct adapter * adapter)1010554c0a3aSHans de Goede void rtw_free_pwrctrl_priv(struct adapter *adapter)
1011554c0a3aSHans de Goede {
1012554c0a3aSHans de Goede }
1013554c0a3aSHans de Goede
rtw_set_ips_deny(struct adapter * padapter,u32 ms)1014554c0a3aSHans de Goede inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms)
1015554c0a3aSHans de Goede {
1016554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
1017554c0a3aSHans de Goede pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ms);
1018554c0a3aSHans de Goede }
1019554c0a3aSHans de Goede
1020554c0a3aSHans de Goede /*
1021554c0a3aSHans de Goede * rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
1022554c0a3aSHans de Goede * @adapter: pointer to struct adapter structure
1023858ea450SR Veera Kumar * @ips_deffer_ms: the ms will prevent from falling into IPS after wakeup
1024554c0a3aSHans de Goede * Return _SUCCESS or _FAIL
1025554c0a3aSHans de Goede */
1026554c0a3aSHans de Goede
_rtw_pwr_wakeup(struct adapter * padapter,u32 ips_deffer_ms,const char * caller)1027554c0a3aSHans de Goede int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller)
1028554c0a3aSHans de Goede {
1029554c0a3aSHans de Goede struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
1030554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj);
1031554c0a3aSHans de Goede struct mlme_priv *pmlmepriv;
1032554c0a3aSHans de Goede int ret = _SUCCESS;
1033554c0a3aSHans de Goede unsigned long start = jiffies;
1034554c0a3aSHans de Goede unsigned long deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms);
1035554c0a3aSHans de Goede
1036554c0a3aSHans de Goede /* for LPS */
1037554c0a3aSHans de Goede LeaveAllPowerSaveMode(padapter);
1038554c0a3aSHans de Goede
1039554c0a3aSHans de Goede /* IPS still bound with primary adapter */
1040554c0a3aSHans de Goede padapter = GET_PRIMARY_ADAPTER(padapter);
1041554c0a3aSHans de Goede pmlmepriv = &padapter->mlmepriv;
1042554c0a3aSHans de Goede
1043554c0a3aSHans de Goede if (time_before(pwrpriv->ips_deny_time, deny_time))
1044554c0a3aSHans de Goede pwrpriv->ips_deny_time = deny_time;
1045554c0a3aSHans de Goede
1046554c0a3aSHans de Goede
1047709c8e49SFabio Aiuto if (pwrpriv->ps_processing)
1048554c0a3aSHans de Goede while (pwrpriv->ps_processing && jiffies_to_msecs(jiffies - start) <= 3000)
10498204b61aSJia-Ju Bai mdelay(10);
1050554c0a3aSHans de Goede
1051709c8e49SFabio Aiuto if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend)
10528ec06b9fSRoss Schmidt while (pwrpriv->bInSuspend && jiffies_to_msecs(jiffies - start) <= 3000
1053709c8e49SFabio Aiuto )
10548204b61aSJia-Ju Bai mdelay(10);
1055554c0a3aSHans de Goede
1056554c0a3aSHans de Goede /* System suspend is not allowed to wakeup */
10572e20a5acSNishka Dasgupta if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) {
1058554c0a3aSHans de Goede ret = _FAIL;
1059554c0a3aSHans de Goede goto exit;
1060554c0a3aSHans de Goede }
1061554c0a3aSHans de Goede
1062554c0a3aSHans de Goede /* block??? */
10632e20a5acSNishka Dasgupta if (pwrpriv->bInternalAutoSuspend && padapter->net_closed) {
1064554c0a3aSHans de Goede ret = _FAIL;
1065554c0a3aSHans de Goede goto exit;
1066554c0a3aSHans de Goede }
1067554c0a3aSHans de Goede
1068554c0a3aSHans de Goede /* I think this should be check in IPS, LPS, autosuspend functions... */
10692e20a5acSNishka Dasgupta if (check_fwstate(pmlmepriv, _FW_LINKED)) {
1070554c0a3aSHans de Goede ret = _SUCCESS;
1071554c0a3aSHans de Goede goto exit;
1072554c0a3aSHans de Goede }
1073554c0a3aSHans de Goede
1074554c0a3aSHans de Goede if (rf_off == pwrpriv->rf_pwrstate) {
1075554c0a3aSHans de Goede {
1076bc21df67SZhansaya Bagdauletkyzy if (ips_leave(padapter) == _FAIL) {
1077554c0a3aSHans de Goede ret = _FAIL;
1078554c0a3aSHans de Goede goto exit;
1079554c0a3aSHans de Goede }
1080554c0a3aSHans de Goede }
1081554c0a3aSHans de Goede }
1082554c0a3aSHans de Goede
1083554c0a3aSHans de Goede /* TODO: the following checking need to be merged... */
10848ec06b9fSRoss Schmidt if (padapter->bDriverStopped || !padapter->bup || !padapter->hw_init_completed) {
1085554c0a3aSHans de Goede ret = false;
1086554c0a3aSHans de Goede goto exit;
1087554c0a3aSHans de Goede }
1088554c0a3aSHans de Goede
1089554c0a3aSHans de Goede exit:
1090554c0a3aSHans de Goede deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms);
1091554c0a3aSHans de Goede if (time_before(pwrpriv->ips_deny_time, deny_time))
1092554c0a3aSHans de Goede pwrpriv->ips_deny_time = deny_time;
1093554c0a3aSHans de Goede return ret;
1094554c0a3aSHans de Goede
1095554c0a3aSHans de Goede }
1096554c0a3aSHans de Goede
rtw_pm_set_lps(struct adapter * padapter,u8 mode)1097554c0a3aSHans de Goede int rtw_pm_set_lps(struct adapter *padapter, u8 mode)
1098554c0a3aSHans de Goede {
1099554c0a3aSHans de Goede int ret = 0;
1100554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
1101554c0a3aSHans de Goede
1102554c0a3aSHans de Goede if (mode < PS_MODE_NUM) {
1103554c0a3aSHans de Goede if (pwrctrlpriv->power_mgnt != mode) {
1104bc21df67SZhansaya Bagdauletkyzy if (mode == PS_MODE_ACTIVE)
1105554c0a3aSHans de Goede LeaveAllPowerSaveMode(padapter);
1106554c0a3aSHans de Goede else
1107554c0a3aSHans de Goede pwrctrlpriv->LpsIdleCount = 2;
1108554c0a3aSHans de Goede
1109554c0a3aSHans de Goede pwrctrlpriv->power_mgnt = mode;
111095b3b423SAastha Gupta pwrctrlpriv->bLeisurePs =
111195b3b423SAastha Gupta pwrctrlpriv->power_mgnt != PS_MODE_ACTIVE;
1112554c0a3aSHans de Goede }
1113554c0a3aSHans de Goede } else
1114554c0a3aSHans de Goede ret = -EINVAL;
1115554c0a3aSHans de Goede
1116554c0a3aSHans de Goede return ret;
1117554c0a3aSHans de Goede }
1118554c0a3aSHans de Goede
rtw_pm_set_ips(struct adapter * padapter,u8 mode)1119554c0a3aSHans de Goede int rtw_pm_set_ips(struct adapter *padapter, u8 mode)
1120554c0a3aSHans de Goede {
1121554c0a3aSHans de Goede struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
1122554c0a3aSHans de Goede
1123554c0a3aSHans de Goede if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) {
1124554c0a3aSHans de Goede rtw_ips_mode_req(pwrctrlpriv, mode);
1125554c0a3aSHans de Goede return 0;
1126554c0a3aSHans de Goede } else if (mode == IPS_NONE) {
1127554c0a3aSHans de Goede rtw_ips_mode_req(pwrctrlpriv, mode);
1128bc21df67SZhansaya Bagdauletkyzy if ((padapter->bSurpriseRemoved == 0) && (rtw_pwr_wakeup(padapter) == _FAIL))
1129554c0a3aSHans de Goede return -EFAULT;
1130554c0a3aSHans de Goede } else
1131554c0a3aSHans de Goede return -EINVAL;
1132554c0a3aSHans de Goede
1133554c0a3aSHans de Goede return 0;
1134554c0a3aSHans de Goede }
1135554c0a3aSHans de Goede
1136554c0a3aSHans de Goede /*
1137554c0a3aSHans de Goede * ATTENTION:
1138554c0a3aSHans de Goede *This function will request pwrctrl LOCK!
1139554c0a3aSHans de Goede */
rtw_ps_deny(struct adapter * padapter,enum ps_deny_reason reason)11407c74d13bSMarco Cesati void rtw_ps_deny(struct adapter *padapter, enum ps_deny_reason reason)
1141554c0a3aSHans de Goede {
1142554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv;
1143554c0a3aSHans de Goede
1144554c0a3aSHans de Goede pwrpriv = adapter_to_pwrctl(padapter);
1145554c0a3aSHans de Goede
114607e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
1147554c0a3aSHans de Goede pwrpriv->ps_deny |= BIT(reason);
114807e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
1149554c0a3aSHans de Goede }
1150554c0a3aSHans de Goede
1151554c0a3aSHans de Goede /*
1152554c0a3aSHans de Goede * ATTENTION:
1153554c0a3aSHans de Goede *This function will request pwrctrl LOCK!
1154554c0a3aSHans de Goede */
rtw_ps_deny_cancel(struct adapter * padapter,enum ps_deny_reason reason)11557c74d13bSMarco Cesati void rtw_ps_deny_cancel(struct adapter *padapter, enum ps_deny_reason reason)
1156554c0a3aSHans de Goede {
1157554c0a3aSHans de Goede struct pwrctrl_priv *pwrpriv;
1158554c0a3aSHans de Goede
1159554c0a3aSHans de Goede pwrpriv = adapter_to_pwrctl(padapter);
1160554c0a3aSHans de Goede
116107e3a844SArnd Bergmann mutex_lock(&pwrpriv->lock);
1162554c0a3aSHans de Goede pwrpriv->ps_deny &= ~BIT(reason);
116307e3a844SArnd Bergmann mutex_unlock(&pwrpriv->lock);
1164554c0a3aSHans de Goede }
1165554c0a3aSHans de Goede
1166554c0a3aSHans de Goede /*
1167554c0a3aSHans de Goede * ATTENTION:
1168554c0a3aSHans de Goede *Before calling this function pwrctrl lock should be occupied already,
1169554c0a3aSHans de Goede *otherwise it may return incorrect value.
1170554c0a3aSHans de Goede */
rtw_ps_deny_get(struct adapter * padapter)1171554c0a3aSHans de Goede u32 rtw_ps_deny_get(struct adapter *padapter)
1172554c0a3aSHans de Goede {
117325e1543bSPayal Kshirsagar return adapter_to_pwrctl(padapter)->ps_deny;
1174554c0a3aSHans de Goede }
1175