1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2010  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  *****************************************************************************/
29 
30 #include "wifi.h"
31 #include "base.h"
32 #include "ps.h"
33 
rtl_ps_enable_nic(struct ieee80211_hw * hw)34 bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
35 {
36 	struct rtl_priv *rtlpriv = rtl_priv(hw);
37 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
38 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
39 	bool init_status = true;
40 
41 	/*<1> reset trx ring */
42 	if (rtlhal->interface == INTF_PCI)
43 		rtlpriv->intf_ops->reset_trx_ring(hw);
44 
45 	if (is_hal_stop(rtlhal))
46 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
47 			 ("Driver is already down!\n"));
48 
49 	/*<2> Enable Adapter */
50 	rtlpriv->cfg->ops->hw_init(hw);
51 	RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
52 	/*init_status = false; */
53 
54 	/*<3> Enable Interrupt */
55 	rtlpriv->cfg->ops->enable_interrupt(hw);
56 
57 	/*<enable timer> */
58 	rtl_watch_dog_timer_callback((unsigned long)hw);
59 
60 	return init_status;
61 }
62 EXPORT_SYMBOL(rtl_ps_enable_nic);
63 
rtl_ps_disable_nic(struct ieee80211_hw * hw)64 bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
65 {
66 	bool status = true;
67 	struct rtl_priv *rtlpriv = rtl_priv(hw);
68 
69 	/*<1> Stop all timer */
70 	rtl_deinit_deferred_work(hw);
71 
72 	/*<2> Disable Interrupt */
73 	rtlpriv->cfg->ops->disable_interrupt(hw);
74 
75 	/*<3> Disable Adapter */
76 	rtlpriv->cfg->ops->hw_disable(hw);
77 
78 	return status;
79 }
80 EXPORT_SYMBOL(rtl_ps_disable_nic);
81 
rtl_ps_set_rf_state(struct ieee80211_hw * hw,enum rf_pwrstate state_toset,u32 changesource,bool protect_or_not)82 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
83 			 enum rf_pwrstate state_toset,
84 			 u32 changesource, bool protect_or_not)
85 {
86 	struct rtl_priv *rtlpriv = rtl_priv(hw);
87 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
88 	enum rf_pwrstate rtstate;
89 	bool actionallowed = false;
90 	u16 rfwait_cnt = 0;
91 	unsigned long flag;
92 
93 	/*protect_or_not = true; */
94 
95 	if (protect_or_not)
96 		goto no_protect;
97 
98 	/*
99 	 *Only one thread can change
100 	 *the RF state at one time, and others
101 	 *should wait to be executed.
102 	 */
103 	while (true) {
104 		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
105 		if (ppsc->rfchange_inprogress) {
106 			spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock,
107 					       flag);
108 
109 			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
110 				 ("RF Change in progress!"
111 				  "Wait to set..state_toset(%d).\n",
112 				  state_toset));
113 
114 			/* Set RF after the previous action is done.  */
115 			while (ppsc->rfchange_inprogress) {
116 				rfwait_cnt++;
117 				mdelay(1);
118 
119 				/*
120 				 *Wait too long, return false to avoid
121 				 *to be stuck here.
122 				 */
123 				if (rfwait_cnt > 100)
124 					return false;
125 			}
126 		} else {
127 			ppsc->rfchange_inprogress = true;
128 			spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock,
129 					       flag);
130 			break;
131 		}
132 	}
133 
134 no_protect:
135 	rtstate = ppsc->rfpwr_state;
136 
137 	switch (state_toset) {
138 	case ERFON:
139 		ppsc->rfoff_reason &= (~changesource);
140 
141 		if ((changesource == RF_CHANGE_BY_HW) &&
142 		    (ppsc->hwradiooff == true)) {
143 			ppsc->hwradiooff = false;
144 		}
145 
146 		if (!ppsc->rfoff_reason) {
147 			ppsc->rfoff_reason = 0;
148 			actionallowed = true;
149 		}
150 
151 		break;
152 
153 	case ERFOFF:
154 
155 		if ((changesource == RF_CHANGE_BY_HW)
156 		    && (ppsc->hwradiooff == false)) {
157 			ppsc->hwradiooff = true;
158 		}
159 
160 		ppsc->rfoff_reason |= changesource;
161 		actionallowed = true;
162 		break;
163 
164 	case ERFSLEEP:
165 		ppsc->rfoff_reason |= changesource;
166 		actionallowed = true;
167 		break;
168 
169 	default:
170 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
171 			 ("switch case not process\n"));
172 		break;
173 	}
174 
175 	if (actionallowed)
176 		rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
177 
178 	if (!protect_or_not) {
179 		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
180 		ppsc->rfchange_inprogress = false;
181 		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
182 	}
183 
184 	return actionallowed;
185 }
186 EXPORT_SYMBOL(rtl_ps_set_rf_state);
187 
_rtl_ps_inactive_ps(struct ieee80211_hw * hw)188 static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
189 {
190 	struct rtl_priv *rtlpriv = rtl_priv(hw);
191 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
192 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
193 
194 	ppsc->swrf_processing = true;
195 
196 	if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
197 		if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
198 		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) &&
199 		    rtlhal->interface == INTF_PCI) {
200 			rtlpriv->intf_ops->disable_aspm(hw);
201 			RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
202 		}
203 	}
204 
205 	rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
206 			    RF_CHANGE_BY_IPS, false);
207 
208 	if (ppsc->inactive_pwrstate == ERFOFF &&
209 	    rtlhal->interface == INTF_PCI) {
210 		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
211 			rtlpriv->intf_ops->enable_aspm(hw);
212 			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
213 		}
214 	}
215 
216 	ppsc->swrf_processing = false;
217 }
218 
rtl_ips_nic_off_wq_callback(void * data)219 void rtl_ips_nic_off_wq_callback(void *data)
220 {
221 	struct rtl_works *rtlworks =
222 	    container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
223 	struct ieee80211_hw *hw = rtlworks->hw;
224 	struct rtl_priv *rtlpriv = rtl_priv(hw);
225 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
226 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
227 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
228 	enum rf_pwrstate rtstate;
229 
230 	if (mac->opmode != NL80211_IFTYPE_STATION) {
231 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
232 			 ("not station return\n"));
233 		return;
234 	}
235 
236 	if (is_hal_stop(rtlhal))
237 		return;
238 
239 	if (rtlpriv->sec.being_setkey)
240 		return;
241 
242 	if (ppsc->inactiveps) {
243 		rtstate = ppsc->rfpwr_state;
244 
245 		/*
246 		 *Do not enter IPS in the following conditions:
247 		 *(1) RF is already OFF or Sleep
248 		 *(2) swrf_processing (indicates the IPS is still under going)
249 		 *(3) Connectted (only disconnected can trigger IPS)
250 		 *(4) IBSS (send Beacon)
251 		 *(5) AP mode (send Beacon)
252 		 *(6) monitor mode (rcv packet)
253 		 */
254 
255 		if (rtstate == ERFON &&
256 		    !ppsc->swrf_processing &&
257 		    (mac->link_state == MAC80211_NOLINK) &&
258 		    !mac->act_scanning) {
259 			RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
260 				 ("IPSEnter(): Turn off RF.\n"));
261 
262 			ppsc->inactive_pwrstate = ERFOFF;
263 			ppsc->in_powersavemode = true;
264 
265 			/*rtl_pci_reset_trx_ring(hw); */
266 			_rtl_ps_inactive_ps(hw);
267 		}
268 	}
269 }
270 
rtl_ips_nic_off(struct ieee80211_hw * hw)271 void rtl_ips_nic_off(struct ieee80211_hw *hw)
272 {
273 	struct rtl_priv *rtlpriv = rtl_priv(hw);
274 
275 	/*
276 	 *because when link with ap, mac80211 will ask us
277 	 *to disable nic quickly after scan before linking,
278 	 *this will cause link failed, so we delay 100ms here
279 	 */
280 	queue_delayed_work(rtlpriv->works.rtl_wq,
281 			   &rtlpriv->works.ips_nic_off_wq, MSECS(100));
282 }
283 
rtl_ips_nic_on(struct ieee80211_hw * hw)284 void rtl_ips_nic_on(struct ieee80211_hw *hw)
285 {
286 	struct rtl_priv *rtlpriv = rtl_priv(hw);
287 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
288 	enum rf_pwrstate rtstate;
289 	unsigned long flags;
290 
291 	spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
292 
293 	if (ppsc->inactiveps) {
294 		rtstate = ppsc->rfpwr_state;
295 
296 		if (rtstate != ERFON &&
297 		    !ppsc->swrf_processing &&
298 		    ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
299 
300 			ppsc->inactive_pwrstate = ERFON;
301 			ppsc->in_powersavemode = false;
302 
303 			_rtl_ps_inactive_ps(hw);
304 		}
305 	}
306 
307 	spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
308 }
309 
310 /*for FW LPS*/
311 
312 /*
313  *Determine if we can set Fw into PS mode
314  *in current condition.Return TRUE if it
315  *can enter PS mode.
316  */
rtl_get_fwlps_doze(struct ieee80211_hw * hw)317 static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
318 {
319 	struct rtl_priv *rtlpriv = rtl_priv(hw);
320 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
321 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
322 	u32 ps_timediff;
323 
324 	ps_timediff = jiffies_to_msecs(jiffies -
325 				       ppsc->last_delaylps_stamp_jiffies);
326 
327 	if (ps_timediff < 2000) {
328 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
329 			 ("Delay enter Fw LPS for DHCP, ARP,"
330 			  " or EAPOL exchanging state.\n"));
331 		return false;
332 	}
333 
334 	if (mac->link_state != MAC80211_LINKED)
335 		return false;
336 
337 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
338 		return false;
339 
340 	return true;
341 }
342 
343 /* Change current and default preamble mode.*/
rtl_lps_set_psmode(struct ieee80211_hw * hw,u8 rt_psmode)344 static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
345 {
346 	struct rtl_priv *rtlpriv = rtl_priv(hw);
347 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
348 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
349 	u8 rpwm_val, fw_pwrmode;
350 
351 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
352 		return;
353 
354 	if (mac->link_state != MAC80211_LINKED)
355 		return;
356 
357 	if (ppsc->dot11_psmode == rt_psmode)
358 		return;
359 
360 	/* Update power save mode configured. */
361 	ppsc->dot11_psmode = rt_psmode;
362 
363 	/*
364 	 *<FW control LPS>
365 	 *1. Enter PS mode
366 	 *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
367 	 *   cmd to set Fw into PS mode.
368 	 *2. Leave PS mode
369 	 *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active
370 	 *   mode and set RPWM to turn RF on.
371 	 */
372 
373 	if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) &&
374 	     ppsc->report_linked) {
375 		bool fw_current_inps;
376 		if (ppsc->dot11_psmode == EACTIVE) {
377 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
378 				 ("FW LPS leave ps_mode:%x\n",
379 				  FW_PS_ACTIVE_MODE));
380 
381 			rpwm_val = 0x0C;	/* RF on */
382 			fw_pwrmode = FW_PS_ACTIVE_MODE;
383 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
384 					(u8 *) (&rpwm_val));
385 			rtlpriv->cfg->ops->set_hw_reg(hw,
386 					HW_VAR_H2C_FW_PWRMODE,
387 					(u8 *) (&fw_pwrmode));
388 			fw_current_inps = false;
389 
390 			rtlpriv->cfg->ops->set_hw_reg(hw,
391 					HW_VAR_FW_PSMODE_STATUS,
392 					(u8 *) (&fw_current_inps));
393 
394 		} else {
395 			if (rtl_get_fwlps_doze(hw)) {
396 				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
397 						("FW LPS enter ps_mode:%x\n",
398 						 ppsc->fwctrl_psmode));
399 
400 				rpwm_val = 0x02;	/* RF off */
401 				fw_current_inps = true;
402 				rtlpriv->cfg->ops->set_hw_reg(hw,
403 						HW_VAR_FW_PSMODE_STATUS,
404 						(u8 *) (&fw_current_inps));
405 				rtlpriv->cfg->ops->set_hw_reg(hw,
406 						HW_VAR_H2C_FW_PWRMODE,
407 						(u8 *) (&ppsc->fwctrl_psmode));
408 
409 				rtlpriv->cfg->ops->set_hw_reg(hw,
410 						HW_VAR_SET_RPWM,
411 						(u8 *) (&rpwm_val));
412 			} else {
413 				/* Reset the power save related parameters. */
414 				ppsc->dot11_psmode = EACTIVE;
415 			}
416 		}
417 	}
418 }
419 
420 /*Enter the leisure power save mode.*/
rtl_lps_enter(struct ieee80211_hw * hw)421 void rtl_lps_enter(struct ieee80211_hw *hw)
422 {
423 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
424 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
425 	struct rtl_priv *rtlpriv = rtl_priv(hw);
426 	unsigned long flag;
427 
428 	if (!(ppsc->fwctrl_lps && ppsc->leisure_ps))
429 		return;
430 
431 	if (rtlpriv->sec.being_setkey)
432 		return;
433 
434 	if (rtlpriv->link_info.busytraffic)
435 		return;
436 
437 	/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
438 	if (mac->cnt_after_linked < 5)
439 		return;
440 
441 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
442 		return;
443 
444 	if (mac->link_state != MAC80211_LINKED)
445 		return;
446 
447 	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
448 
449 	if (ppsc->leisure_ps) {
450 		/* Idle for a while if we connect to AP a while ago. */
451 		if (mac->cnt_after_linked >= 2) {
452 			if (ppsc->dot11_psmode == EACTIVE) {
453 				RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
454 					("Enter 802.11 power save mode...\n"));
455 
456 				rtl_lps_set_psmode(hw, EAUTOPS);
457 			}
458 		}
459 	}
460 	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
461 }
462 
463 /*Leave the leisure power save mode.*/
rtl_lps_leave(struct ieee80211_hw * hw)464 void rtl_lps_leave(struct ieee80211_hw *hw)
465 {
466 	struct rtl_priv *rtlpriv = rtl_priv(hw);
467 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
468 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
469 	unsigned long flag;
470 
471 	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
472 
473 	if (ppsc->fwctrl_lps && ppsc->leisure_ps) {
474 		if (ppsc->dot11_psmode != EACTIVE) {
475 
476 			/*FIX ME */
477 			rtlpriv->cfg->ops->enable_interrupt(hw);
478 
479 			if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
480 			    RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) &&
481 			    rtlhal->interface == INTF_PCI) {
482 				rtlpriv->intf_ops->disable_aspm(hw);
483 				RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM);
484 			}
485 
486 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
487 				 ("Busy Traffic,Leave 802.11 power save..\n"));
488 
489 			rtl_lps_set_psmode(hw, EACTIVE);
490 		}
491 	}
492 	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
493 }
494