xref: /linux/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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