• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012  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 <linux/export.h>
31 #include "wifi.h"
32 #include "base.h"
33 #include "ps.h"
34 
rtl_ps_enable_nic(struct ieee80211_hw * hw)35 bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
36 {
37 	struct rtl_priv *rtlpriv = rtl_priv(hw);
38 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
39 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
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 	if (rtlpriv->cfg->ops->hw_init(hw))
51 		return 1;
52 	RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
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 true;
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 	struct rtl_priv *rtlpriv = rtl_priv(hw);
67 
68 	/*<1> Stop all timer */
69 	rtl_deinit_deferred_work(hw);
70 
71 	/*<2> Disable Interrupt */
72 	rtlpriv->cfg->ops->disable_interrupt(hw);
73 	tasklet_kill(&rtlpriv->works.irq_tasklet);
74 
75 	/*<3> Disable Adapter */
76 	rtlpriv->cfg->ops->hw_disable(hw);
77 
78 	return true;
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)82 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
83 			 enum rf_pwrstate state_toset,
84 			 u32 changesource)
85 {
86 	struct rtl_priv *rtlpriv = rtl_priv(hw);
87 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
88 	bool actionallowed = false;
89 
90 	switch (state_toset) {
91 	case ERFON:
92 		ppsc->rfoff_reason &= (~changesource);
93 
94 		if ((changesource == RF_CHANGE_BY_HW) &&
95 		    (ppsc->hwradiooff)) {
96 			ppsc->hwradiooff = false;
97 		}
98 
99 		if (!ppsc->rfoff_reason) {
100 			ppsc->rfoff_reason = 0;
101 			actionallowed = true;
102 		}
103 
104 		break;
105 
106 	case ERFOFF:
107 
108 		if ((changesource == RF_CHANGE_BY_HW) && !ppsc->hwradiooff) {
109 			ppsc->hwradiooff = true;
110 		}
111 
112 		ppsc->rfoff_reason |= changesource;
113 		actionallowed = true;
114 		break;
115 
116 	case ERFSLEEP:
117 		ppsc->rfoff_reason |= changesource;
118 		actionallowed = true;
119 		break;
120 
121 	default:
122 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
123 			 "switch case not processed\n");
124 		break;
125 	}
126 
127 	if (actionallowed)
128 		rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
129 
130 	return actionallowed;
131 }
132 EXPORT_SYMBOL(rtl_ps_set_rf_state);
133 
_rtl_ps_inactive_ps(struct ieee80211_hw * hw)134 static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
135 {
136 	struct rtl_priv *rtlpriv = rtl_priv(hw);
137 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
138 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
139 
140 	ppsc->swrf_processing = true;
141 
142 	if (ppsc->inactive_pwrstate == ERFON &&
143 	    rtlhal->interface == INTF_PCI) {
144 		if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
145 		    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
146 		    rtlhal->interface == INTF_PCI) {
147 			rtlpriv->intf_ops->disable_aspm(hw);
148 			RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
149 		}
150 	}
151 
152 	rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, RF_CHANGE_BY_IPS);
153 
154 	if (ppsc->inactive_pwrstate == ERFOFF &&
155 	    rtlhal->interface == INTF_PCI) {
156 		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
157 			!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
158 			rtlpriv->intf_ops->enable_aspm(hw);
159 			RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
160 		}
161 	}
162 
163 	ppsc->swrf_processing = false;
164 }
165 
rtl_ips_nic_off_wq_callback(void * data)166 void rtl_ips_nic_off_wq_callback(void *data)
167 {
168 	struct rtl_works *rtlworks =
169 	    container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
170 	struct ieee80211_hw *hw = rtlworks->hw;
171 	struct rtl_priv *rtlpriv = rtl_priv(hw);
172 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
173 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
174 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
175 	enum rf_pwrstate rtstate;
176 
177 	if (mac->opmode != NL80211_IFTYPE_STATION) {
178 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
179 			 "not station return\n");
180 		return;
181 	}
182 
183 	if (mac->p2p_in_use)
184 		return;
185 
186 	if (mac->link_state > MAC80211_NOLINK)
187 		return;
188 
189 	if (is_hal_stop(rtlhal))
190 		return;
191 
192 	if (rtlpriv->sec.being_setkey)
193 		return;
194 
195 	if (rtlpriv->cfg->ops->bt_coex_off_before_lps)
196 		rtlpriv->cfg->ops->bt_coex_off_before_lps(hw);
197 
198 	if (ppsc->inactiveps) {
199 		rtstate = ppsc->rfpwr_state;
200 
201 		/*
202 		 *Do not enter IPS in the following conditions:
203 		 *(1) RF is already OFF or Sleep
204 		 *(2) swrf_processing (indicates the IPS is still under going)
205 		 *(3) Connectted (only disconnected can trigger IPS)
206 		 *(4) IBSS (send Beacon)
207 		 *(5) AP mode (send Beacon)
208 		 *(6) monitor mode (rcv packet)
209 		 */
210 
211 		if (rtstate == ERFON &&
212 		    !ppsc->swrf_processing &&
213 		    (mac->link_state == MAC80211_NOLINK) &&
214 		    !mac->act_scanning) {
215 			RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
216 				 "IPSEnter(): Turn off RF\n");
217 
218 			ppsc->inactive_pwrstate = ERFOFF;
219 			ppsc->in_powersavemode = true;
220 
221 			/*rtl_pci_reset_trx_ring(hw); */
222 			_rtl_ps_inactive_ps(hw);
223 		}
224 	}
225 }
226 
rtl_ips_nic_off(struct ieee80211_hw * hw)227 void rtl_ips_nic_off(struct ieee80211_hw *hw)
228 {
229 	struct rtl_priv *rtlpriv = rtl_priv(hw);
230 
231 	/*
232 	 *because when link with ap, mac80211 will ask us
233 	 *to disable nic quickly after scan before linking,
234 	 *this will cause link failed, so we delay 100ms here
235 	 */
236 	queue_delayed_work(rtlpriv->works.rtl_wq,
237 			   &rtlpriv->works.ips_nic_off_wq, MSECS(100));
238 }
239 
240 /* NOTICE: any opmode should exc nic_on, or disable without
241  * nic_on may something wrong, like adhoc TP
242  */
rtl_ips_nic_on(struct ieee80211_hw * hw)243 void rtl_ips_nic_on(struct ieee80211_hw *hw)
244 {
245 	struct rtl_priv *rtlpriv = rtl_priv(hw);
246 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
247 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
248 	enum rf_pwrstate rtstate;
249 	unsigned long flags;
250 
251 	if (mac->opmode != NL80211_IFTYPE_STATION)
252 		return;
253 
254 	spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
255 
256 	if (ppsc->inactiveps) {
257 		rtstate = ppsc->rfpwr_state;
258 
259 		if (rtstate != ERFON &&
260 		    !ppsc->swrf_processing &&
261 		    ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
262 
263 			ppsc->inactive_pwrstate = ERFON;
264 			ppsc->in_powersavemode = false;
265 
266 			_rtl_ps_inactive_ps(hw);
267 		}
268 	}
269 
270 	spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
271 }
272 
273 /*for FW LPS*/
274 
275 /*
276  *Determine if we can set Fw into PS mode
277  *in current condition.Return TRUE if it
278  *can enter PS mode.
279  */
rtl_get_fwlps_doze(struct ieee80211_hw * hw)280 static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
281 {
282 	struct rtl_priv *rtlpriv = rtl_priv(hw);
283 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
284 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
285 	u32 ps_timediff;
286 
287 	ps_timediff = jiffies_to_msecs(jiffies -
288 				       ppsc->last_delaylps_stamp_jiffies);
289 
290 	if (ps_timediff < 2000) {
291 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
292 			 "Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n");
293 		return false;
294 	}
295 
296 	if (mac->link_state != MAC80211_LINKED)
297 		return false;
298 
299 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
300 		return false;
301 
302 	return true;
303 }
304 
305 /* Change current and default preamble mode.*/
rtl_lps_set_psmode(struct ieee80211_hw * hw,u8 rt_psmode)306 static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
307 {
308 	struct rtl_priv *rtlpriv = rtl_priv(hw);
309 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
310 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
311 	bool enter_fwlps;
312 
313 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
314 		return;
315 
316 	if (mac->link_state != MAC80211_LINKED)
317 		return;
318 
319 	if (ppsc->dot11_psmode == rt_psmode)
320 		return;
321 
322 	/* Update power save mode configured. */
323 	ppsc->dot11_psmode = rt_psmode;
324 
325 	/*
326 	 *<FW control LPS>
327 	 *1. Enter PS mode
328 	 *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
329 	 *   cmd to set Fw into PS mode.
330 	 *2. Leave PS mode
331 	 *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active
332 	 *   mode and set RPWM to turn RF on.
333 	 */
334 
335 	if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
336 		if (ppsc->dot11_psmode == EACTIVE) {
337 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
338 				 "FW LPS leave ps_mode:%x\n",
339 				 FW_PS_ACTIVE_MODE);
340 			enter_fwlps = false;
341 			ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
342 			ppsc->smart_ps = 0;
343 			rtlpriv->cfg->ops->set_hw_reg(hw,
344 						HW_VAR_FW_LPS_ACTION,
345 						(u8 *)(&enter_fwlps));
346 			if (ppsc->p2p_ps_info.opp_ps)
347 				rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
348 
349 		} else {
350 			if (rtl_get_fwlps_doze(hw)) {
351 				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
352 					 "FW LPS enter ps_mode:%x\n",
353 					 ppsc->fwctrl_psmode);
354 				enter_fwlps = true;
355 				ppsc->pwr_mode = ppsc->fwctrl_psmode;
356 				ppsc->smart_ps = 2;
357 				rtlpriv->cfg->ops->set_hw_reg(hw,
358 							HW_VAR_FW_LPS_ACTION,
359 							(u8 *)(&enter_fwlps));
360 
361 			} else {
362 				/* Reset the power save related parameters. */
363 				ppsc->dot11_psmode = EACTIVE;
364 			}
365 		}
366 	}
367 }
368 
369 /*Enter the leisure power save mode.*/
rtl_lps_enter(struct ieee80211_hw * hw)370 void rtl_lps_enter(struct ieee80211_hw *hw)
371 {
372 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
373 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
374 	struct rtl_priv *rtlpriv = rtl_priv(hw);
375 
376 	if (!ppsc->fwctrl_lps)
377 		return;
378 
379 	if (rtlpriv->sec.being_setkey)
380 		return;
381 
382 	if (rtlpriv->link_info.busytraffic)
383 		return;
384 
385 	/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
386 	if (mac->cnt_after_linked < 5)
387 		return;
388 
389 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
390 		return;
391 
392 	if (mac->link_state != MAC80211_LINKED)
393 		return;
394 
395 	mutex_lock(&rtlpriv->locks.ps_mutex);
396 
397 	/* Idle for a while if we connect to AP a while ago. */
398 	if (mac->cnt_after_linked >= 2) {
399 		if (ppsc->dot11_psmode == EACTIVE) {
400 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
401 				 "Enter 802.11 power save mode...\n");
402 
403 			rtl_lps_set_psmode(hw, EAUTOPS);
404 		}
405 	}
406 
407 	mutex_unlock(&rtlpriv->locks.ps_mutex);
408 }
409 
410 /*Leave the leisure power save mode.*/
rtl_lps_leave(struct ieee80211_hw * hw)411 void rtl_lps_leave(struct ieee80211_hw *hw)
412 {
413 	struct rtl_priv *rtlpriv = rtl_priv(hw);
414 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
415 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
416 
417 	mutex_lock(&rtlpriv->locks.ps_mutex);
418 
419 	if (ppsc->fwctrl_lps) {
420 		if (ppsc->dot11_psmode != EACTIVE) {
421 
422 			/*FIX ME */
423 			rtlpriv->cfg->ops->enable_interrupt(hw);
424 
425 			if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
426 			    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
427 			    rtlhal->interface == INTF_PCI) {
428 				rtlpriv->intf_ops->disable_aspm(hw);
429 				RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
430 			}
431 
432 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
433 				 "Busy Traffic,Leave 802.11 power save..\n");
434 
435 			rtl_lps_set_psmode(hw, EACTIVE);
436 		}
437 	}
438 	mutex_unlock(&rtlpriv->locks.ps_mutex);
439 }
440 
441 /* For sw LPS*/
rtl_swlps_beacon(struct ieee80211_hw * hw,void * data,unsigned int len)442 void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
443 {
444 	struct rtl_priv *rtlpriv = rtl_priv(hw);
445 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
446 	struct ieee80211_hdr *hdr = data;
447 	struct ieee80211_tim_ie *tim_ie;
448 	u8 *tim;
449 	u8 tim_len;
450 	bool u_buffed;
451 	bool m_buffed;
452 
453 	if (mac->opmode != NL80211_IFTYPE_STATION)
454 		return;
455 
456 	if (!rtlpriv->psc.swctrl_lps)
457 		return;
458 
459 	if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
460 		return;
461 
462 	if (!rtlpriv->psc.sw_ps_enabled)
463 		return;
464 
465 	if (rtlpriv->psc.fwctrl_lps)
466 		return;
467 
468 	if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
469 		return;
470 
471 	/* check if this really is a beacon */
472 	if (!ieee80211_is_beacon(hdr->frame_control))
473 		return;
474 
475 	/* min. beacon length + FCS_LEN */
476 	if (len <= 40 + FCS_LEN)
477 		return;
478 
479 	/* and only beacons from the associated BSSID, please */
480 	if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
481 		return;
482 
483 	rtlpriv->psc.last_beacon = jiffies;
484 
485 	tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
486 	if (!tim)
487 		return;
488 
489 	if (tim[1] < sizeof(*tim_ie))
490 		return;
491 
492 	tim_len = tim[1];
493 	tim_ie = (struct ieee80211_tim_ie *) &tim[2];
494 
495 	if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
496 		rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
497 
498 	/* Check whenever the PHY can be turned off again. */
499 
500 	/* 1. What about buffered unicast traffic for our AID? */
501 	u_buffed = ieee80211_check_tim(tim_ie, tim_len,
502 				       rtlpriv->mac80211.assoc_id);
503 
504 	/* 2. Maybe the AP wants to send multicast/broadcast data? */
505 	m_buffed = tim_ie->bitmap_ctrl & 0x01;
506 	rtlpriv->psc.multi_buffered = m_buffed;
507 
508 	/* unicast will process by mac80211 through
509 	 * set ~IEEE80211_CONF_PS, So we just check
510 	 * multicast frames here */
511 	if (!m_buffed) {
512 		/* back to low-power land. and delay is
513 		 * prevent null power save frame tx fail */
514 		queue_delayed_work(rtlpriv->works.rtl_wq,
515 				&rtlpriv->works.ps_work, MSECS(5));
516 	} else {
517 		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
518 			 "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed);
519 	}
520 }
521 
rtl_swlps_rf_awake(struct ieee80211_hw * hw)522 void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
523 {
524 	struct rtl_priv *rtlpriv = rtl_priv(hw);
525 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
526 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
527 
528 	if (!rtlpriv->psc.swctrl_lps)
529 		return;
530 	if (mac->link_state != MAC80211_LINKED)
531 		return;
532 
533 	if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
534 		RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
535 		rtlpriv->intf_ops->disable_aspm(hw);
536 		RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
537 	}
538 
539 	mutex_lock(&rtlpriv->locks.ps_mutex);
540 	rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS);
541 	mutex_unlock(&rtlpriv->locks.ps_mutex);
542 }
543 
rtl_swlps_rfon_wq_callback(void * data)544 void rtl_swlps_rfon_wq_callback(void *data)
545 {
546 	struct rtl_works *rtlworks =
547 	    container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
548 	struct ieee80211_hw *hw = rtlworks->hw;
549 
550 	rtl_swlps_rf_awake(hw);
551 }
552 
rtl_swlps_rf_sleep(struct ieee80211_hw * hw)553 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
554 {
555 	struct rtl_priv *rtlpriv = rtl_priv(hw);
556 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
557 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
558 	u8 sleep_intv;
559 
560 	if (!rtlpriv->psc.sw_ps_enabled)
561 		return;
562 
563 	if ((rtlpriv->sec.being_setkey) ||
564 	    (mac->opmode == NL80211_IFTYPE_ADHOC))
565 		return;
566 
567 	/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
568 	if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
569 		return;
570 
571 	if (rtlpriv->link_info.busytraffic)
572 		return;
573 
574 	mutex_lock(&rtlpriv->locks.ps_mutex);
575 	rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS);
576 	mutex_unlock(&rtlpriv->locks.ps_mutex);
577 
578 	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
579 		!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
580 		rtlpriv->intf_ops->enable_aspm(hw);
581 		RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
582 	}
583 
584 	/* here is power save alg, when this beacon is DTIM
585 	 * we will set sleep time to dtim_period * n;
586 	 * when this beacon is not DTIM, we will set sleep
587 	 * time to sleep_intv = rtlpriv->psc.dtim_counter or
588 	 * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
589 
590 	if (rtlpriv->psc.dtim_counter == 0) {
591 		if (hw->conf.ps_dtim_period == 1)
592 			sleep_intv = hw->conf.ps_dtim_period * 2;
593 		else
594 			sleep_intv = hw->conf.ps_dtim_period;
595 	} else {
596 		sleep_intv = rtlpriv->psc.dtim_counter;
597 	}
598 
599 	if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
600 		sleep_intv = MAX_SW_LPS_SLEEP_INTV;
601 
602 	/* this print should always be dtim_conter = 0 &
603 	 * sleep  = dtim_period, that meaons, we should
604 	 * awake before every dtim */
605 	RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
606 		 "dtim_counter:%x will sleep :%d beacon_intv\n",
607 		 rtlpriv->psc.dtim_counter, sleep_intv);
608 
609 	/* we tested that 40ms is enough for sw & hw sw delay */
610 	queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
611 			MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
612 }
613 
614 
rtl_swlps_wq_callback(void * data)615 void rtl_swlps_wq_callback(void *data)
616 {
617 	struct rtl_works *rtlworks = container_of_dwork_rtl(data,
618 				     struct rtl_works,
619 				     ps_work);
620 	struct ieee80211_hw *hw = rtlworks->hw;
621 	struct rtl_priv *rtlpriv = rtl_priv(hw);
622 	bool ps = false;
623 
624 	ps = (hw->conf.flags & IEEE80211_CONF_PS);
625 
626 	/* we can sleep after ps null send ok */
627 	if (rtlpriv->psc.state_inap) {
628 		rtl_swlps_rf_sleep(hw);
629 
630 		if (rtlpriv->psc.state && !ps) {
631 			rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies -
632 					rtlpriv->psc.last_action);
633 		}
634 
635 		if (ps)
636 			rtlpriv->psc.last_slept = jiffies;
637 
638 		rtlpriv->psc.last_action = jiffies;
639 		rtlpriv->psc.state = ps;
640 	}
641 }
642 
rtl_p2p_noa_ie(struct ieee80211_hw * hw,void * data,unsigned int len)643 static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
644 			   unsigned int len)
645 {
646 	struct rtl_priv *rtlpriv = rtl_priv(hw);
647 	struct ieee80211_mgmt *mgmt = (void *)data;
648 	struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
649 	u8 *pos, *end, *ie;
650 	u16 noa_len;
651 	static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
652 	u8 noa_num, index, i, noa_index = 0;
653 	bool find_p2p_ie = false , find_p2p_ps_ie = false;
654 	pos = (u8 *)mgmt->u.beacon.variable;
655 	end = data + len;
656 	ie = NULL;
657 
658 	while (pos + 1 < end) {
659 		if (pos + 2 + pos[1] > end)
660 			return;
661 
662 		if (pos[0] == 221 && pos[1] > 4) {
663 			if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
664 				ie = pos + 2+4;
665 				break;
666 			}
667 		}
668 		pos += 2 + pos[1];
669 	}
670 
671 	if (ie == NULL)
672 		return;
673 	find_p2p_ie = true;
674 	/*to find noa ie*/
675 	while (ie + 1 < end) {
676 		noa_len = READEF2BYTE(&ie[1]);
677 		if (ie + 3 + ie[1] > end)
678 			return;
679 
680 		if (ie[0] == 12) {
681 			find_p2p_ps_ie = true;
682 			if ((noa_len - 2) % 13 != 0) {
683 				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
684 					 "P2P notice of absence: invalid length.%d\n",
685 					 noa_len);
686 				return;
687 			} else {
688 				noa_num = (noa_len - 2) / 13;
689 			}
690 			noa_index = ie[3];
691 			if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
692 			    P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
693 				RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
694 					 "update NOA ie.\n");
695 				p2pinfo->noa_index = noa_index;
696 				p2pinfo->opp_ps = (ie[4] >> 7);
697 				p2pinfo->ctwindow = ie[4] & 0x7F;
698 				p2pinfo->noa_num = noa_num;
699 				index = 5;
700 				for (i = 0; i < noa_num; i++) {
701 					p2pinfo->noa_count_type[i] =
702 						 READEF1BYTE(ie+index);
703 					index += 1;
704 					p2pinfo->noa_duration[i] =
705 						 READEF4BYTE(ie+index);
706 					index += 4;
707 					p2pinfo->noa_interval[i] =
708 						 READEF4BYTE(ie+index);
709 					index += 4;
710 					p2pinfo->noa_start_time[i] =
711 						 READEF4BYTE(ie+index);
712 					index += 4;
713 				}
714 
715 				if (p2pinfo->opp_ps == 1) {
716 					p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
717 					/* Driver should wait LPS entering
718 					 * CTWindow
719 					 */
720 					if (rtlpriv->psc.fw_current_inpsmode)
721 						rtl_p2p_ps_cmd(hw,
722 							       P2P_PS_ENABLE);
723 				} else if (p2pinfo->noa_num > 0) {
724 					p2pinfo->p2p_ps_mode = P2P_PS_NOA;
725 					rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
726 				} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
727 					rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
728 				}
729 			}
730 		break;
731 		}
732 		ie += 3 + noa_len;
733 	}
734 
735 	if (find_p2p_ie == true) {
736 		if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
737 		    (find_p2p_ps_ie == false))
738 			rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
739 	}
740 }
741 
rtl_p2p_action_ie(struct ieee80211_hw * hw,void * data,unsigned int len)742 static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
743 			      unsigned int len)
744 {
745 	struct rtl_priv *rtlpriv = rtl_priv(hw);
746 	struct ieee80211_mgmt *mgmt = (void *)data;
747 	struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
748 	u8 noa_num, index, i, noa_index = 0;
749 	u8 *pos, *end, *ie;
750 	u16 noa_len;
751 	static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
752 
753 	pos = (u8 *)&mgmt->u.action.category;
754 	end = data + len;
755 	ie = NULL;
756 
757 	if (pos[0] == 0x7f) {
758 		if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
759 			ie = pos + 3+4;
760 	}
761 
762 	if (ie == NULL)
763 		return;
764 
765 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n");
766 	/*to find noa ie*/
767 	while (ie + 1 < end) {
768 		noa_len = READEF2BYTE(&ie[1]);
769 		if (ie + 3 + ie[1] > end)
770 			return;
771 
772 		if (ie[0] == 12) {
773 			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n");
774 			RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
775 				      ie, noa_len);
776 			if ((noa_len - 2) % 13 != 0) {
777 				RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
778 					 "P2P notice of absence: invalid length.%d\n",
779 					 noa_len);
780 				return;
781 			} else {
782 				noa_num = (noa_len - 2) / 13;
783 			}
784 			noa_index = ie[3];
785 			if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
786 			    P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
787 				p2pinfo->noa_index = noa_index;
788 				p2pinfo->opp_ps = (ie[4] >> 7);
789 				p2pinfo->ctwindow = ie[4] & 0x7F;
790 				p2pinfo->noa_num = noa_num;
791 				index = 5;
792 				for (i = 0; i < noa_num; i++) {
793 					p2pinfo->noa_count_type[i] =
794 							 READEF1BYTE(ie+index);
795 					index += 1;
796 					p2pinfo->noa_duration[i] =
797 							 READEF4BYTE(ie+index);
798 					index += 4;
799 					p2pinfo->noa_interval[i] =
800 							 READEF4BYTE(ie+index);
801 					index += 4;
802 					p2pinfo->noa_start_time[i] =
803 							 READEF4BYTE(ie+index);
804 					index += 4;
805 				}
806 
807 				if (p2pinfo->opp_ps == 1) {
808 					p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
809 					/* Driver should wait LPS entering
810 					 * CTWindow
811 					 */
812 					if (rtlpriv->psc.fw_current_inpsmode)
813 						rtl_p2p_ps_cmd(hw,
814 							       P2P_PS_ENABLE);
815 				} else if (p2pinfo->noa_num > 0) {
816 					p2pinfo->p2p_ps_mode = P2P_PS_NOA;
817 					rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
818 				} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
819 					rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
820 				}
821 			}
822 		break;
823 		}
824 		ie += 3 + noa_len;
825 	}
826 }
827 
rtl_p2p_ps_cmd(struct ieee80211_hw * hw,u8 p2p_ps_state)828 void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
829 {
830 	struct rtl_priv *rtlpriv = rtl_priv(hw);
831 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
832 	struct rtl_p2p_ps_info  *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
833 
834 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n", p2p_ps_state);
835 	switch (p2p_ps_state) {
836 	case P2P_PS_DISABLE:
837 		p2pinfo->p2p_ps_state = p2p_ps_state;
838 		rtlpriv->cfg->ops->set_hw_reg(hw,
839 				 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
840 				 (u8 *)(&p2p_ps_state));
841 
842 		p2pinfo->noa_index = 0;
843 		p2pinfo->ctwindow = 0;
844 		p2pinfo->opp_ps = 0;
845 		p2pinfo->noa_num = 0;
846 		p2pinfo->p2p_ps_mode = P2P_PS_NONE;
847 		if (rtlps->fw_current_inpsmode == true) {
848 			if (rtlps->smart_ps == 0) {
849 				rtlps->smart_ps = 2;
850 				rtlpriv->cfg->ops->set_hw_reg(hw,
851 					 HW_VAR_H2C_FW_PWRMODE,
852 					 (u8 *)(&rtlps->pwr_mode));
853 			}
854 		}
855 		break;
856 	case P2P_PS_ENABLE:
857 		if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
858 			p2pinfo->p2p_ps_state = p2p_ps_state;
859 
860 			if (p2pinfo->ctwindow > 0) {
861 				if (rtlps->smart_ps != 0) {
862 					rtlps->smart_ps = 0;
863 					rtlpriv->cfg->ops->set_hw_reg(hw,
864 						 HW_VAR_H2C_FW_PWRMODE,
865 						 (u8 *)(&rtlps->pwr_mode));
866 				}
867 			}
868 			rtlpriv->cfg->ops->set_hw_reg(hw,
869 				 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
870 				 (u8 *)(&p2p_ps_state));
871 		}
872 		break;
873 	case P2P_PS_SCAN:
874 	case P2P_PS_SCAN_DONE:
875 	case P2P_PS_ALLSTASLEEP:
876 		if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
877 			p2pinfo->p2p_ps_state = p2p_ps_state;
878 			rtlpriv->cfg->ops->set_hw_reg(hw,
879 				 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
880 				 (u8 *)(&p2p_ps_state));
881 		}
882 		break;
883 	default:
884 		break;
885 	}
886 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
887 		 "ctwindow %x oppps %x\n", p2pinfo->ctwindow, p2pinfo->opp_ps);
888 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
889 		 "count %x duration %x index %x interval %x start time %x noa num %x\n",
890 		 p2pinfo->noa_count_type[0], p2pinfo->noa_duration[0],
891 		 p2pinfo->noa_index, p2pinfo->noa_interval[0],
892 		 p2pinfo->noa_start_time[0], p2pinfo->noa_num);
893 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n");
894 }
895 
rtl_p2p_info(struct ieee80211_hw * hw,void * data,unsigned int len)896 void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
897 {
898 	struct rtl_priv *rtlpriv = rtl_priv(hw);
899 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
900 	struct ieee80211_hdr *hdr = (void *)data;
901 
902 	if (!mac->p2p)
903 		return;
904 	if (mac->link_state != MAC80211_LINKED)
905 		return;
906 	/* min. beacon length + FCS_LEN */
907 	if (len <= 40 + FCS_LEN)
908 		return;
909 
910 	/* and only beacons from the associated BSSID, please */
911 	if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
912 		return;
913 
914 	/* check if this really is a beacon */
915 	if (!(ieee80211_is_beacon(hdr->frame_control) ||
916 	      ieee80211_is_probe_resp(hdr->frame_control) ||
917 	      ieee80211_is_action(hdr->frame_control)))
918 		return;
919 
920 	if (ieee80211_is_action(hdr->frame_control))
921 		rtl_p2p_action_ie(hw, data, len - FCS_LEN);
922 	else
923 		rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
924 }
925