cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ps.c (26023B)


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