Example #1
0
File: core.c Project: 7799/linux
/*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw)
{
	int err;
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));

	if (!is_hal_stop(rtlhal))
		return 0;
	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
		return 0;
	mutex_lock(&rtlpriv->locks.conf_mutex);
	err = rtlpriv->intf_ops->adapter_start(hw);
	if (!err)
		rtl_watch_dog_timer_callback((unsigned long)hw);
	mutex_unlock(&rtlpriv->locks.conf_mutex);
	return err;
}
Example #2
0
void rtl_ips_nic_off_wq_callback(void *data)
{
	struct rtl_works *rtlworks =
	    container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
	struct ieee80211_hw *hw = rtlworks->hw;
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	enum rf_pwrstate rtstate;

	if (mac->opmode != NL80211_IFTYPE_STATION) {
		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
			 "not station return\n");
		return;
	}

	if (mac->link_state > MAC80211_NOLINK)
		return;

	if (is_hal_stop(rtlhal))
		return;

	if (rtlpriv->sec.being_setkey)
		return;

	if (ppsc->inactiveps) {
		rtstate = ppsc->rfpwr_state;


		if (rtstate == ERFON &&
		    !ppsc->swrf_processing &&
		    (mac->link_state == MAC80211_NOLINK) &&
		    !mac->act_scanning) {
			RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
				 "IPSEnter(): Turn off RF\n");

			ppsc->inactive_pwrstate = ERFOFF;
			ppsc->in_powersavemode = true;

			
			_rtl_ps_inactive_ps(hw);
		}
	}
}
Example #3
0
static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
		      struct rtl_tcb_desc *dummy)
{
	struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
	__le16 fc = hdr->frame_control;
	u16 hw_queue;

	if (unlikely(is_hal_stop(rtlhal)))
		goto err_free;
	hw_queue = rtlusb->usb_mq_to_hwq(fc, skb_get_queue_mapping(skb));
	_rtl_usb_tx_preprocess(hw, skb, hw_queue);
	_rtl_usb_transmit(hw, skb, hw_queue);
	return NETDEV_TX_OK;

err_free:
	dev_kfree_skb_any(skb);
	return NETDEV_TX_OK;
}
static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	struct rtl_tcb_desc tcb_desc;
	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));

	if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
		goto err_free;

	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
		goto err_free;

	if (!rtlpriv->intf_ops->waitq_insert(hw, skb))
		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);

	return;

err_free:
	dev_kfree_skb_any(skb);
}
Example #5
0
int rtl_send_smps_action(struct ieee80211_hw *hw,
		struct ieee80211_sta *sta, u8 *da, u8 *bssid,
		enum ieee80211_smps_mode smps)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid);
	struct rtl_tcb_desc tcb_desc;
	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));

	if (rtlpriv->mac80211.act_scanning)
		goto err_free;

	if (!sta)
		goto err_free;

	if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
		goto err_free;

	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
		goto err_free;

	/* this is a type = mgmt * stype = action frame */
	if (skb) {
		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
		struct rtl_sta_info *sta_entry =
			(struct rtl_sta_info *) sta->drv_priv;
		sta_entry->mimo_ps = smps;
		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);

		info->control.rates[0].idx = 0;
		info->control.sta = sta;
		info->band = hw->conf.channel->band;
		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
	}
err_free:
	return 0;
}
Example #6
0
/*<delete in kernel end>*/
static void rtl_op_tx(struct ieee80211_hw *hw,
		      struct ieee80211_tx_control *control,
		      struct sk_buff *skb)
/*<delete in kernel start>*/
#endif
/*<delete in kernel end>*/
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	struct rtl_tcb_desc tcb_desc;
	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));

	if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
		goto err_free;

	if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
		goto err_free;

/*<delete in kernel start>*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
	if (!rtlpriv->intf_ops->waitq_insert(hw, skb))
		rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
#else
/*<delete in kernel end>*/
	if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb))
	        rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc);
/*<delete in kernel start>*/
#endif
/*<delete in kernel end>*/
	return;

err_free:
	dev_kfree_skb_any(skb);
	return;
}
Example #7
0
void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_phy *rtlphy = &(rtlpriv->phy);
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	u8 reg_bw_opmode;
	u8 reg_prsr_rsc;

	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
		 ("Switch to %s bandwidth\n",
		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
		  "20MHz" : "40MHz"))

	if (is_hal_stop(rtlhal)) {
		rtlphy->set_bwmode_inprogress = false;
		return;
	}

	reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
	reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);

	switch (rtlphy->current_chan_bw) {
	case HT_CHANNEL_WIDTH_20:
		reg_bw_opmode |= BW_OPMODE_20MHZ;
		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
		break;
	case HT_CHANNEL_WIDTH_20_40:
		reg_bw_opmode &= ~BW_OPMODE_20MHZ;
		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
		reg_prsr_rsc =
		    (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
		break;
	default:
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
		break;
	}

	switch (rtlphy->current_chan_bw) {
	case HT_CHANNEL_WIDTH_20:
		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
		break;
	case HT_CHANNEL_WIDTH_20_40:
		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);

		rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
			      (mac->cur_40_prime_sc >> 1));
		rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);

		rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
			      (mac->cur_40_prime_sc ==
			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
		break;
	default:
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
		break;
	}
	rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
	rtlphy->set_bwmode_inprogress = false;
	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
}
Example #8
0
/*********************************************************
 *
 * wq & timer callback functions
 *
 *********************************************************/
void rtl_watchdog_wq_callback(void *data)
{
	struct rtl_works *rtlworks = container_of_dwork_rtl(data,
							    struct rtl_works,
							    watchdog_wq);
	struct ieee80211_hw *hw = rtlworks->hw;
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));

	bool b_busytraffic = false;
	bool b_higher_busytraffic = false;
	bool b_higher_busyrxtraffic = false;
	bool b_higher_busytxtraffic = false;

	u8 idx = 0;
	u32 rx_cnt_inp4eriod = 0;
	u32 tx_cnt_inp4eriod = 0;
	u32 aver_rx_cnt_inperiod = 0;
	u32 aver_tx_cnt_inperiod = 0;

	bool benter_ps = false;

	if (is_hal_stop(rtlhal))
		return;

	/* <1> Determine if action frame is allowed */
	if (mac->link_state > MAC80211_NOLINK) {
		if (mac->cnt_after_linked < 20)
			mac->cnt_after_linked++;
	} else {
		mac->cnt_after_linked = 0;
	}

	/* <2> DM */
	rtlpriv->cfg->ops->dm_watchdog(hw);

	/*
	 *<3> to check if traffic busy, if
	 * busytraffic we don't change channel
	 */
	if (mac->link_state >= MAC80211_LINKED) {

		/* (1) get aver_rx_cnt_inperiod & aver_tx_cnt_inperiod */
		for (idx = 0; idx <= 2; idx++) {
			rtlpriv->link_info.num_rx_in4period[idx] =
			    rtlpriv->link_info.num_rx_in4period[idx + 1];
			rtlpriv->link_info.num_tx_in4period[idx] =
			    rtlpriv->link_info.num_tx_in4period[idx + 1];
		}
		rtlpriv->link_info.num_rx_in4period[3] =
		    rtlpriv->link_info.num_rx_inperiod;
		rtlpriv->link_info.num_tx_in4period[3] =
		    rtlpriv->link_info.num_tx_inperiod;
		for (idx = 0; idx <= 3; idx++) {
			rx_cnt_inp4eriod +=
			    rtlpriv->link_info.num_rx_in4period[idx];
			tx_cnt_inp4eriod +=
			    rtlpriv->link_info.num_tx_in4period[idx];
		}
		aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4;
		aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;

		/* (2) check traffic busy */
		if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100)
			b_busytraffic = true;

		/* Higher Tx/Rx data. */
		if (aver_rx_cnt_inperiod > 4000 ||
		    aver_tx_cnt_inperiod > 4000) {
			b_higher_busytraffic = true;

			/* Extremely high Rx data. */
			if (aver_rx_cnt_inperiod > 5000)
				b_higher_busyrxtraffic = true;
			else
				b_higher_busytxtraffic = false;
		}

		if (((rtlpriv->link_info.num_rx_inperiod +
		      rtlpriv->link_info.num_tx_inperiod) > 8) ||
		    (rtlpriv->link_info.num_rx_inperiod > 2))
			benter_ps = false;
		else
			benter_ps = true;

		/* LeisurePS only work in infra mode. */
		if (benter_ps)
			rtl_lps_enter(hw);
		else
			rtl_lps_leave(hw);
	}

	rtlpriv->link_info.num_rx_inperiod = 0;
	rtlpriv->link_info.num_tx_inperiod = 0;

	rtlpriv->link_info.b_busytraffic = b_busytraffic;
	rtlpriv->link_info.b_higher_busytraffic = b_higher_busytraffic;
	rtlpriv->link_info.b_higher_busyrxtraffic = b_higher_busyrxtraffic;

}
static void _rtl92s_dm_refresh_rateadaptive_mask( struct ieee80211_hw *hw )
{
	struct rtl_priv *rtlpriv = rtl_priv( hw );
	struct rtl_hal *rtlhal = rtl_hal( rtl_priv( hw ) );
	struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) );
	struct rate_adaptive *ra = &( rtlpriv->ra );
	struct ieee80211_sta *sta = NULL;
	u32 low_rssi_thresh = 0;
	u32 middle_rssi_thresh = 0;
	u32 high_rssi_thresh = 0;

	if ( is_hal_stop( rtlhal ) )
		return;

	if ( !rtlpriv->dm.useramask )
		return;

	if ( hal_get_firmwareversion( rtlpriv ) >= 61 &&
	    !rtlpriv->dm.inform_fw_driverctrldm ) {
		rtl92s_phy_set_fw_cmd( hw, FW_CMD_CTRL_DM_BY_DRIVER );
		rtlpriv->dm.inform_fw_driverctrldm = true;
	}

	if ( ( mac->link_state == MAC80211_LINKED ) &&
	    ( mac->opmode == NL80211_IFTYPE_STATION ) ) {
		switch ( ra->pre_ratr_state ) {
		case DM_RATR_STA_HIGH:
			high_rssi_thresh = 40;
			middle_rssi_thresh = 30;
			low_rssi_thresh = 20;
			break;
		case DM_RATR_STA_MIDDLE:
			high_rssi_thresh = 44;
			middle_rssi_thresh = 30;
			low_rssi_thresh = 20;
			break;
		case DM_RATR_STA_LOW:
			high_rssi_thresh = 44;
			middle_rssi_thresh = 34;
			low_rssi_thresh = 20;
			break;
		case DM_RATR_STA_ULTRALOW:
			high_rssi_thresh = 44;
			middle_rssi_thresh = 34;
			low_rssi_thresh = 24;
			break;
		default:
			high_rssi_thresh = 44;
			middle_rssi_thresh = 34;
			low_rssi_thresh = 24;
			break;
		}

		if ( rtlpriv->dm.undec_sm_pwdb > ( long )high_rssi_thresh ) {
			ra->ratr_state = DM_RATR_STA_HIGH;
		} else if ( rtlpriv->dm.undec_sm_pwdb >
			   ( long )middle_rssi_thresh ) {
			ra->ratr_state = DM_RATR_STA_LOW;
		} else if ( rtlpriv->dm.undec_sm_pwdb >
			   ( long )low_rssi_thresh ) {
			ra->ratr_state = DM_RATR_STA_LOW;
		} else {
			ra->ratr_state = DM_RATR_STA_ULTRALOW;
		}

		if ( ra->pre_ratr_state != ra->ratr_state ) {
			RT_TRACE( rtlpriv, COMP_RATE, DBG_LOUD,
				 "RSSI = %ld RSSI_LEVEL = %d PreState = %d, CurState = %d\n",
				 rtlpriv->dm.undec_sm_pwdb, ra->ratr_state,
				 ra->pre_ratr_state, ra->ratr_state );

			rcu_read_lock();
			sta = rtl_find_sta( hw, mac->bssid );
			if ( sta )
				rtlpriv->cfg->ops->update_rate_tbl( hw, sta,
							   ra->ratr_state );
			rcu_read_unlock();

			ra->pre_ratr_state = ra->ratr_state;
		}
	}
}
Example #10
0
void rtl92e_ips_nic_off_wq_callback(void *data)
{
	struct rtl_works *rtlworks =
	    container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
	struct ieee80211_hw *hw = rtlworks->hw;
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	enum rf_pwrstate rtstate;

	if (mac->opmode != NL80211_IFTYPE_STATION) {
		RT_TRACE(COMP_ERR, DBG_WARNING, ("not station return\n"));
		return;
	}

	if (mac->p2p_in_use)
		return;

	if (mac->link_state > MAC80211_NOLINK)
		return;

	if (is_hal_stop(rtlhal))
		return;

	if (rtlpriv->sec.being_setkey)
		return;

	if (rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps)
		rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps(hw);

	if (ppsc->b_inactiveps) {
		rtstate = ppsc->rfpwr_state;

		/*
		 *Do not enter IPS in the following conditions:
		 *(1) RF is already OFF or Sleep
		 *(2) b_swrf_processing (indicates the IPS is still under going)
		 *(3) Connectted (only disconnected can trigger IPS)
		 *(4) IBSS (send Beacon)
		 *(5) AP mode (send Beacon)
		 *(6) monitor mode (rcv packet)
		 */

		if (rtstate == ERFON &&
		    !ppsc->b_swrf_processing &&
		    (mac->link_state == MAC80211_NOLINK) &&
		    !mac->act_scanning) {
			RT_TRACE(COMP_RF, DBG_LOUD,
				 ("IPSEnter(): Turn off RF.\n"));

			ppsc->inactive_pwrstate = ERFOFF;
			ppsc->b_in_powersavemode = true;

			/* call before RF off */
			if (rtlpriv->cfg->ops->get_btc_status())
				rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
									ppsc->inactive_pwrstate);

			/*rtl92e_pci_reset_trx_ring(hw); */
			_rtl_ps_inactive_ps(hw);
		}
	}
}
Example #11
0
static void rtl8723ae_dm_refresh_rate_adaptive_mask( struct ieee80211_hw *hw )
{
	struct rtl_priv *rtlpriv = rtl_priv( hw );
	struct rtl_hal *rtlhal = rtl_hal( rtl_priv( hw ) );
	struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) );
	struct rate_adaptive *p_ra = &( rtlpriv->ra );
	u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
	struct ieee80211_sta *sta = NULL;

	if ( is_hal_stop( rtlhal ) ) {
		RT_TRACE( rtlpriv, COMP_RATE, DBG_LOUD,
			 " driver is going to unload\n" );
		return;
	}

	if ( !rtlpriv->dm.useramask ) {
		RT_TRACE( rtlpriv, COMP_RATE, DBG_LOUD,
			 " driver does not control rate adaptive mask\n" );
		return;
	}

	if ( mac->link_state == MAC80211_LINKED &&
	    mac->opmode == NL80211_IFTYPE_STATION ) {
		switch ( p_ra->pre_ratr_state ) {
		case DM_RATR_STA_HIGH:
			high_rssithresh_for_ra = 50;
			low_rssithresh_for_ra = 20;
			break;
		case DM_RATR_STA_MIDDLE:
			high_rssithresh_for_ra = 55;
			low_rssithresh_for_ra = 20;
			break;
		case DM_RATR_STA_LOW:
			high_rssithresh_for_ra = 50;
			low_rssithresh_for_ra = 25;
			break;
		default:
			high_rssithresh_for_ra = 50;
			low_rssithresh_for_ra = 20;
			break;
		}

		if ( rtlpriv->dm.undec_sm_pwdb > high_rssithresh_for_ra )
			p_ra->ratr_state = DM_RATR_STA_HIGH;
		else if ( rtlpriv->dm.undec_sm_pwdb > low_rssithresh_for_ra )
			p_ra->ratr_state = DM_RATR_STA_MIDDLE;
		else
			p_ra->ratr_state = DM_RATR_STA_LOW;

		if ( p_ra->pre_ratr_state != p_ra->ratr_state ) {
			RT_TRACE( rtlpriv, COMP_RATE, DBG_LOUD,
				 "RSSI = %ld\n",
				 rtlpriv->dm.undec_sm_pwdb );
			RT_TRACE( rtlpriv, COMP_RATE, DBG_LOUD,
				 "RSSI_LEVEL = %d\n", p_ra->ratr_state );
			RT_TRACE( rtlpriv, COMP_RATE, DBG_LOUD,
				 "PreState = %d, CurState = %d\n",
				 p_ra->pre_ratr_state, p_ra->ratr_state );

			rcu_read_lock();
			sta = rtl_find_sta( hw, mac->bssid );
			if ( sta )
				rtlpriv->cfg->ops->update_rate_tbl( hw, sta,
							   p_ra->ratr_state );
			rcu_read_unlock();

			p_ra->pre_ratr_state = p_ra->ratr_state;
		}
	}
}
void rtl_watchdog_wq_callback(void *data)
{
	struct rtl_works *rtlworks = container_of_dwork_rtl(data,
							    struct rtl_works,
							    watchdog_wq);
	struct ieee80211_hw *hw = rtlworks->hw;
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	bool busytraffic = false;
	bool higher_busytraffic = false;
	bool higher_busyrxtraffic = false;
	u8 idx, tid;
	u32 rx_cnt_inp4eriod = 0;
	u32 tx_cnt_inp4eriod = 0;
	u32 aver_rx_cnt_inperiod = 0;
	u32 aver_tx_cnt_inperiod = 0;
	u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
	u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
	bool enter_ps = false;

	if (is_hal_stop(rtlhal))
		return;

	
	if (mac->link_state > MAC80211_NOLINK) {
		if (mac->cnt_after_linked < 20)
			mac->cnt_after_linked++;
	} else {
		mac->cnt_after_linked = 0;
	}

	if (mac->link_state >= MAC80211_LINKED) {

		
		for (idx = 0; idx <= 2; idx++) {
			rtlpriv->link_info.num_rx_in4period[idx] =
			    rtlpriv->link_info.num_rx_in4period[idx + 1];
			rtlpriv->link_info.num_tx_in4period[idx] =
			    rtlpriv->link_info.num_tx_in4period[idx + 1];
		}
		rtlpriv->link_info.num_rx_in4period[3] =
		    rtlpriv->link_info.num_rx_inperiod;
		rtlpriv->link_info.num_tx_in4period[3] =
		    rtlpriv->link_info.num_tx_inperiod;
		for (idx = 0; idx <= 3; idx++) {
			rx_cnt_inp4eriod +=
			    rtlpriv->link_info.num_rx_in4period[idx];
			tx_cnt_inp4eriod +=
			    rtlpriv->link_info.num_tx_in4period[idx];
		}
		aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4;
		aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;

		
		if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100)
			busytraffic = true;

		
		if (aver_rx_cnt_inperiod > 4000 ||
		    aver_tx_cnt_inperiod > 4000) {
			higher_busytraffic = true;

			
			if (aver_rx_cnt_inperiod > 5000)
				higher_busyrxtraffic = true;
		}

		
		for (tid = 0; tid <= 7; tid++) {
			for (idx = 0; idx <= 2; idx++)
				rtlpriv->link_info.tidtx_in4period[tid][idx] =
				  rtlpriv->link_info.tidtx_in4period[tid]
				  [idx + 1];
			rtlpriv->link_info.tidtx_in4period[tid][3] =
				rtlpriv->link_info.tidtx_inperiod[tid];

			for (idx = 0; idx <= 3; idx++)
				tidtx_inp4eriod[tid] +=
				  rtlpriv->link_info.tidtx_in4period[tid][idx];
			aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4;
			if (aver_tidtx_inperiod[tid] > 5000)
				rtlpriv->link_info.higher_busytxtraffic[tid] =
						   true;
			else
				rtlpriv->link_info.higher_busytxtraffic[tid] =
						   false;
		}

		if (((rtlpriv->link_info.num_rx_inperiod +
		      rtlpriv->link_info.num_tx_inperiod) > 8) ||
		    (rtlpriv->link_info.num_rx_inperiod > 2))
			enter_ps = false;
		else
			enter_ps = true;

		
		if (enter_ps)
			rtl_lps_enter(hw);
		else
			rtl_lps_leave(hw);
	}

	rtlpriv->link_info.num_rx_inperiod = 0;
	rtlpriv->link_info.num_tx_inperiod = 0;
	for (tid = 0; tid <= 7; tid++)
		rtlpriv->link_info.tidtx_inperiod[tid] = 0;

	rtlpriv->link_info.busytraffic = busytraffic;
	rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
	rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;

	
	rtlpriv->cfg->ops->dm_watchdog(hw);
}