/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 *****************************************************************************/
#define _HAL_STA_C_
#include "hal_headers.h"

void
_hal_sta_rssi_init(struct rtw_phl_stainfo_t *sta)
{
	sta->hal_sta->rssi_stat.assoc_rssi = 0;
	sta->hal_sta->rssi_stat.ma_rssi = 0;
}

static enum rtw_hal_status
_hal_bfee_init(struct hal_info_t *hal_info,
	       struct rtw_phl_stainfo_t *sta)
{
	enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE;
	struct rtw_wifi_role_link_t *rlink = NULL;
	bool enable_bfee = false;

	do {
		if(NULL == sta)
			break;

		rlink = sta->rlink;
		if (NULL == rlink)
			break;

		/*only init BFee when wrole cap's bfee and sta cap 's bfer matched */
		if ((rlink->protocol_cap.he_su_bfme ||
		     rlink->protocol_cap.he_mu_bfme) &&
		    (sta->asoc_cap.he_su_bfmr || sta->asoc_cap.he_mu_bfmr)) {
			enable_bfee = true;
		}

		if ((rlink->protocol_cap.vht_su_bfme ||
		     rlink->protocol_cap.vht_mu_bfme) &&
		    (sta->asoc_cap.vht_su_bfmr || sta->asoc_cap.vht_mu_bfmr)) {
			enable_bfee = true;
		}

		if (rlink->protocol_cap.ht_su_bfme &&
		    sta->asoc_cap.ht_su_bfmr)
			enable_bfee = true;

		if (true == enable_bfee) {
			/* BFee Functions */
			if (RTW_HAL_STATUS_SUCCESS !=
				hal_bf_hw_mac_init_bfee(hal_info, rlink->hw_band))
			{
				PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
					  "%s : Init HW MAC BFee Fail\n",
					  __func__);
				break;
			}
			/* BFee CSI parameters*/
			hal_info->hal_com->csi_para_ctrl_sel = false;
			if (RTW_HAL_STATUS_SUCCESS !=
				hal_bf_set_bfee_csi_para(hal_info,
					hal_info->hal_com->csi_para_ctrl_sel,
					sta)) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
					  "%s : Set BFee CSI Para Fail\n",
					  __func__);
				break;
			}
#ifdef RTW_WKARD_DYNAMIC_BFEE_CAP
			/* BB Workaround */
			rtw_hal_bb_dcr_en(hal_info, true);
#endif

			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s : Enable HW BFee Function Success\n",
				  __func__);
		}
		hstatus = RTW_HAL_STATUS_SUCCESS;
	} while (0);

	return hstatus;
}

static enum rtw_hal_status
_hal_set_default_cctrl_tbl(struct hal_info_t *hal_info,
				 struct rtw_phl_stainfo_t *sta)
{
	enum rtw_hal_status sts = RTW_HAL_STATUS_FAILURE;
	struct rtw_hal_mac_ax_cctl_info cctrl, cctl_mask;

	_os_mem_set(hal_to_drvpriv(hal_info), &cctrl, 0,
			sizeof(struct rtw_hal_mac_ax_cctl_info));
	_os_mem_set(hal_to_drvpriv(hal_info), &cctl_mask, 0,
			sizeof(struct rtw_hal_mac_ax_cctl_info));
	if (NULL == sta)
		goto out;
	sts = rtw_hal_bb_cfg_config_cmac_tbl(hal_info, sta, &cctrl, &cctl_mask);
	if (sts != RTW_HAL_STATUS_SUCCESS) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: fill cmac table of bb failed)\n",
			__func__);
		goto out;
	}
#ifdef CONFIG_PHL_DEFAULT_MGNT_Q_RPT_EN
	cctrl.mgq_rpt_en = 1;
	cctl_mask.mgq_rpt_en = 1;
#endif
	sts = rtw_hal_cmc_tbl_cfg(hal_info, &cctrl ,&cctl_mask, sta->macid);
out:
	return sts;
}

static enum rtw_hal_status
_hal_update_cctrl_tbl(struct hal_info_t *hal_info,
			    struct rtw_phl_stainfo_t *sta)
{
	struct rtw_wifi_role_t *wrole = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	struct role_link_cap_t *cap = NULL;
	enum rtw_hal_status sts = RTW_HAL_STATUS_FAILURE;
	struct rtw_hal_mac_ax_cctl_info cctrl, cctl_info_mask;
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	phl_fun_monitor_start(&start_t, true, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	_os_mem_set(hal_to_drvpriv(hal_info), &cctrl, 0, sizeof(struct rtw_hal_mac_ax_cctl_info));
	_os_mem_set(hal_to_drvpriv(hal_info), &cctl_info_mask, 0, sizeof(struct rtw_hal_mac_ax_cctl_info));

	if (NULL == sta)
		goto out;
	wrole = sta->wrole;
	rlink = sta->rlink;
	cap = &rlink->cap;

	sts = rtw_hal_bb_cfg_config_cmac_tbl(hal_info, sta, &cctrl,
						&cctl_info_mask);
	if (sts != RTW_HAL_STATUS_SUCCESS) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: fill cmac table of bb failed)\n",
			__func__);
		goto out;
	}
	/*TODO - update cctrl tab from stainfo*/
	cctrl.disrtsfb = 1;
	cctl_info_mask.disrtsfb = 1;

	cctrl.disdatafb = 1;
	cctl_info_mask.disdatafb = 1;

	/*
	if (!cctrl.disdatafb)
		cctrl.arfr_ctrl = rtw_hal_bb_get_arfr_idx(hal_info, sta);
	*/

	if (cap->rty_lmt_rts == 0xFF) {
		cctrl.rts_txcnt_lmt_sel = 0;
	} else {
		cctrl.rts_txcnt_lmt_sel = 1;
		cctrl.rts_txcnt_lmt = cap->rty_lmt_rts & 0xF;
		cctl_info_mask.rts_txcnt_lmt = 0xF;
	}
	cctl_info_mask.rts_txcnt_lmt_sel = 1;
	cctrl.rts_rty_lowest_rate = (sta->chandef.band == BAND_ON_24G) ? (RTW_DATA_RATE_CCK1) : (RTW_DATA_RATE_OFDM6);
	cctl_info_mask.rts_rty_lowest_rate = 0xF;

	if (cap->rty_lmt == 0xFF) {
		cctrl.data_txcnt_lmt_sel = 0;
	} else {
		cctrl.data_txcnt_lmt_sel = 1;
		cctrl.data_tx_cnt_lmt = cap->rty_lmt & 0x3F;
		cctl_info_mask.data_tx_cnt_lmt = 0x3F;
	}
	cctl_info_mask.data_txcnt_lmt_sel = 1;

	cctrl.max_agg_num_sel = 1;
	cctl_info_mask.max_agg_num_sel = 1;

	cctrl.max_agg_num = sta->asoc_cap.num_ampdu - 1;
	cctl_info_mask.max_agg_num = 0xFF;

	cctrl.ampdu_density = sta->asoc_cap.ampdu_density;
	cctl_info_mask.ampdu_density = 0xF;

	if (cctrl.max_agg_num <= 0x3F)
		cctrl.ba_bmap = 0; /* 64 */
	else if (cctrl.max_agg_num > 0x3F && cctrl.max_agg_num <= 0x7F)
		cctrl.ba_bmap = 1; /* 128*/
	else if ( cctrl.max_agg_num > 0x7F && cctrl.max_agg_num <= 0xFF)
		cctrl.ba_bmap = 2; /* 256 */
	cctl_info_mask.ba_bmap = 0x3;

	if (rtw_phl_role_is_client_category(sta->wrole)) {
		cctrl.uldl = 1;
		cctl_info_mask.uldl = 1;
	} else {
		cctrl.uldl = 0;
		cctl_info_mask.uldl = 1;
	}

	cctrl.multi_port_id = rlink->hw_port;
	cctl_info_mask.multi_port_id = 0x7;

	if (rtw_phl_role_is_ap_category(wrole)) {
		cctrl.data_dcm = 0; /*(sta->asoc_cap.dcm_max_const_rx > 0)*/
		cctl_info_mask.data_dcm = 1;
	}

	cctrl.rts_en = sta->rts_en;
	cctrl.hw_rts_en = sta->hw_rts_en;
	cctrl.cts2self_en = sta->cts2self;
	cctrl.cca_rts = sta->rts_cca_mode;

	cctl_info_mask.hw_rts_en = 0x1;
	cctl_info_mask.rts_en = 0x1;
	cctl_info_mask.cts2self_en = 0x1;
	cctl_info_mask.cca_rts = 0x3;

	if (sta->asoc_cap.pkt_padding == 3) {
		/* follow PPE threshold */
		u8 ppe16 = 0, ppe8 = 0;
		u8 nss = sta->asoc_cap.nss_rx;

		/* bw = 20MHz */
		ppe16 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_20] & 0x7);
		ppe8 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_20]>>3) & 0x7;

		if ((ppe16 != 7) && (ppe8 == 7)) {
			cctrl.nominal_pkt_padding = 2;
			cctl_info_mask.nominal_pkt_padding = 0x3;
		} else if (ppe8 != 7) {
			cctrl.nominal_pkt_padding = 1;
			cctl_info_mask.nominal_pkt_padding = 0x3;
		} else {
			cctrl.nominal_pkt_padding = 0;
			cctl_info_mask.nominal_pkt_padding = 0x3;
		}
		/* bw = 40MHz */
		ppe16 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_40] & 0x7);
		ppe8 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_40]>>3) & 0x7;

		if ((ppe16 != 7) && (ppe8 == 7)) {
			cctrl.nominal_pkt_padding40 = 2;
			cctl_info_mask.nominal_pkt_padding40 = 0x3;
		} else if (ppe8 != 7) {
			cctrl.nominal_pkt_padding40 = 1;
			cctl_info_mask.nominal_pkt_padding40 = 0x3;
		} else {
			cctrl.nominal_pkt_padding40 = 0;
			cctl_info_mask.nominal_pkt_padding40 = 0x3;
		}
		/* bw = 80MHz */
		ppe16 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_80] & 0x7);
		ppe8 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_80]>>3) & 0x7;

		if ((ppe16 != 7) && (ppe8 == 7)) {
			cctrl.nominal_pkt_padding80 = 2;
			cctl_info_mask.nominal_pkt_padding80 = 0x3;
		} else if (ppe8 != 7) {
			cctrl.nominal_pkt_padding80 = 1;
			cctl_info_mask.nominal_pkt_padding80 = 0x3;
		} else {
			cctrl.nominal_pkt_padding80 = 0;
			cctl_info_mask.nominal_pkt_padding80 = 0x3;
		}
		/* bw = 160MHz */
		ppe16 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_160] & 0x7);
		ppe8 = (sta->asoc_cap.ppe_thr[nss - 1][CHANNEL_WIDTH_160]>>3) & 0x7;

		if ((ppe16 != 7) && (ppe8 == 7)) {
			cctrl.nominal_pkt_padding160 = 2;
			cctl_info_mask.nominal_pkt_padding160 = 0x3;
		} else if (ppe8 != 7) {
			cctrl.nominal_pkt_padding160 = 1;
			cctl_info_mask.nominal_pkt_padding160 = 0x3;
		} else {
			cctrl.nominal_pkt_padding160 = 0;
			cctl_info_mask.nominal_pkt_padding160 = 0x3;
		}
	} else {
		cctrl.nominal_pkt_padding = sta->asoc_cap.pkt_padding;
		cctrl.nominal_pkt_padding40 = sta->asoc_cap.pkt_padding;
		cctrl.nominal_pkt_padding80 = sta->asoc_cap.pkt_padding;
		cctrl.nominal_pkt_padding160 = sta->asoc_cap.pkt_padding;
		cctl_info_mask.nominal_pkt_padding = 0x3;
		cctl_info_mask.nominal_pkt_padding40 = 0x3;
		cctl_info_mask.nominal_pkt_padding80 = 0x3;
		cctl_info_mask.nominal_pkt_padding160 = 0x3;
	}

	if (sta->wmode&WLAN_MD_11AX) {
          	/**
                 * bsr_queue_size_format:
                 * 1: buffer status unit is 802.11, HE mode
                 * 0: buffer status unit is 802.11, legacy mode
                 **/
		cctrl.bsr_queue_size_format = 1;
		cctl_info_mask.bsr_queue_size_format = 1;

		if (sta->asoc_cap.he_ldpc)
			cctrl.data_ldpc = 1;
	} else if (sta->wmode & WLAN_MD_11AC) {
		if (sta->asoc_cap.vht_ldpc)
			cctrl.data_ldpc = 1;
	} else if (sta->wmode & WLAN_MD_11N) {
		if (sta->asoc_cap.ht_ldpc)
			cctrl.data_ldpc = 1;
	}
	cctl_info_mask.data_ldpc = 1;

	if (sta->set_rts_init_rate > 0) {
		cctrl.rtsrate = sta->set_rts_init_rate - 1;
		cctl_info_mask.rtsrate = 0x1FF;
	}

	sts = rtw_hal_cmc_tbl_cfg(hal_info, &cctrl, &cctl_info_mask, sta->macid);

out:
#ifdef DBG_DBCC_MONITOR_TIME
	phl_fun_monitor_end(hal_info->phl_com, &start_t, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	return sts;
}

enum rtw_hal_status
rtw_hal_upd_ampdu_cctrl_info(void *hal, struct rtw_phl_stainfo_t *sta)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status sts = RTW_HAL_STATUS_FAILURE;
	struct rtw_hal_mac_ax_cctl_info cctrl, cctl_info_mask;

	_os_mem_set(hal_to_drvpriv(hal_info), &cctrl, 0, sizeof(struct rtw_hal_mac_ax_cctl_info));
	_os_mem_set(hal_to_drvpriv(hal_info), &cctl_info_mask, 0, sizeof(struct rtw_hal_mac_ax_cctl_info));

	if (NULL == sta)
		goto out;

	cctrl.max_agg_num_sel = 1;
	cctl_info_mask.max_agg_num_sel = 1;

	cctrl.max_agg_num = sta->asoc_cap.num_ampdu - 1;
	cctl_info_mask.max_agg_num = 0xFF;

	if (cctrl.max_agg_num <= 0x3F)
		cctrl.ba_bmap = 0; /* 64 */
	else if (cctrl.max_agg_num > 0x3F && cctrl.max_agg_num <= 0x7F)
		cctrl.ba_bmap = 1; /* 128*/
	else if ( cctrl.max_agg_num > 0x7F && cctrl.max_agg_num <= 0xFF)
		cctrl.ba_bmap = 2; /* 256 */
	cctl_info_mask.ba_bmap = 0x3;

	sts = rtw_hal_cmc_tbl_cfg(hal_info, &cctrl, &cctl_info_mask, sta->macid);

out:
	return sts;
}

enum rtw_hal_status
rtw_hal_cfg_rsc(void *hal, struct rtw_phl_stainfo_t *sta, u8 rsc_cfg)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	struct rtw_wifi_role_link_t *rlink = sta->rlink;
	enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE;

	hsts = rtw_hal_mac_set_rsc_cfg(hal_info->hal_com, rsc_cfg, rlink->hw_band);

	return hsts;
}



enum rtw_hal_status
rtw_hal_cfg_rrsr_ref_rate_sel(void *hal, struct rtw_phl_stainfo_t *sta, bool ref_rate_sel)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE;

	hsts = rtw_hal_mac_set_rrsr_ref_rate_sel(hal_info->hal_com, ref_rate_sel, sta->rlink->hw_band);

	return hsts;
}


enum rtw_hal_status
rtw_hal_cfg_tx_ampdu(void *hal, struct rtw_phl_stainfo_t *sta)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE;

	/* update ampdu configuration */
	if (256 >= sta->asoc_cap.num_ampdu) {
		hsts = rtw_hal_mac_set_hw_ampdu_cfg(hal_info,
		                                    sta->rlink->hw_band,
		                                    sta->asoc_cap.num_ampdu,
		                                    0xA5);
	} else {
		PHL_WARN("%s not consider this case : num_ampdu(%u), please check \n",
			__func__, sta->asoc_cap.num_ampdu);
	}

	if (RTW_HAL_STATUS_SUCCESS != hsts)
		goto out;
out:
	return hsts;
}


static enum rtw_hal_status
_hal_update_dctrl_tbl(struct hal_info_t *hal_info,
		      struct rtw_phl_stainfo_t *sta)
{
	enum rtw_hal_status sts = RTW_HAL_STATUS_FAILURE;
	struct mac_ax_dctl_info dctrl, dctl_info_mask;
#if defined(CONFIG_RTW_TX_HW_AMSDU_HW_MERGE_MODE) || defined(CONFIG_RTW_TX_HW_AMSDU_SW_MERGE_MODE)
	u8 amsdu_max_len = 0;
#endif
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	phl_fun_monitor_start(&start_t, true, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	if (NULL == sta)
		goto out;

	_os_mem_set(hal_to_drvpriv(hal_info), &dctrl, 0, sizeof(struct mac_ax_dctl_info));
	_os_mem_set(hal_to_drvpriv(hal_info), &dctl_info_mask, 0, sizeof(struct mac_ax_dctl_info));

#ifdef CONFIG_RTW_TX_HW_HDR_CONV
	/* mhdr_len: qos = 26, nonqos = 24 */
	sts = rtw_hal_mac_hdr_conv_tx_macid_en(hal_info, sta->macid, 0, 1, 26, 0);
	if (sts != RTW_HAL_STATUS_SUCCESS)
		goto out;

	dctrl.vlan_tag_sel = 0;	/* [TODO] process vlan_tag */
	dctrl.htc_order = 0;	/* [TODO] process htc_order */

	dctl_info_mask.vlan_tag_sel = 0x3;
	dctl_info_mask.htc_order = 0x1;

#if defined(CONFIG_RTW_TX_HW_AMSDU_HW_MERGE_MODE) || defined(CONFIG_RTW_TX_HW_AMSDU_SW_MERGE_MODE)
	amsdu_max_len = (sta->asoc_cap.max_amsdu_len > 0) ? HWAMSDU_MAX_LEN_7920 : HWAMSDU_MAX_LEN_4024;

	sts = rtw_hal_mac_hwamsdu_max_len(hal_info, sta->macid, amsdu_max_len);
	if (sts != RTW_HAL_STATUS_SUCCESS)
		goto out;

	sts = rtw_hal_mac_hwamsdu_macid_en(hal_info, sta->macid, 1);
	if (sts != RTW_HAL_STATUS_SUCCESS)
		goto out;
#endif
#endif

#if defined(CONFIG_PHL_CSUM_OFFLOAD_RX) || defined(CONFIG_PHL_CSUM_OFFLOAD_TX)
	dctrl.chksum_offload_en = 1;
	dctl_info_mask.chksum_offload_en = 1;
	dctrl.with_llc = 1;
	dctl_info_mask.with_llc = 1;
#endif /*CONFIG_PHL_CSUM_OFFLOAD_RX*/

	sts = rtw_hal_dmc_tbl_cfg(hal_info, &dctrl, &dctl_info_mask, sta->macid);

out:
#ifdef DBG_DBCC_MONITOR_TIME
	phl_fun_monitor_end(hal_info->phl_com, &start_t, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	return sts;
}

enum rtw_hal_status
_hal_update_ba_cam(struct hal_info_t *hal_info, u8 valid, u16 macid,
                   u8 dialog_token, u16 timeout, u16 start_seq_num, u16 ba_policy,
                   u16 tid, u16 buf_size, u8 camid, u8 band_idx, u8 uid, bool is_std)
{
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	void *drv = hal_to_drvpriv(hal_info);
	struct mac_ax_bacam_info ba_cam = {0};
	FUNCIN();
	_os_mem_set(drv, &ba_cam, 0, sizeof(ba_cam));
	ba_cam.valid = valid;
	ba_cam.init_req = 1;
	ba_cam.entry_idx = camid;
	ba_cam.entry_idx_v1 = camid;
	ba_cam.tid = tid;
	ba_cam.macid = (u8)macid;
	ba_cam.std_entry_en = is_std;
	/**
	 * uid_value valid when std_entry_en = 0,
	 * it indicate the mapping of Rx UID in MAC/PHY intf and this temp entry.
	 **/
	ba_cam.uid_value = uid;
	ba_cam.band_sel = band_idx;
	if (buf_size > 64)
		ba_cam.bmap_size = 4;
	else
		ba_cam.bmap_size = 0;
	ba_cam.ssn = start_seq_num;

	PHL_INFO("[BACAM] ba_cam.valid = %d, ba_cam.init_req = %d, ba_cam.entry_idx = %d\n",
			 ba_cam.valid,
			 ba_cam.init_req,
			 ba_cam.entry_idx);
	PHL_INFO("[BACAM] ba_cam.tid = %d, ba_cam.macid = %d, ba_cam.bmap_size = %d\n",
			 ba_cam.tid,
			 ba_cam.macid,
			 ba_cam.bmap_size);
	PHL_INFO("[BACAM] ba_cam.ssn = 0x%X, ba_cam.entry_idx_v1 =%d\n",
			 ba_cam.ssn,
			 ba_cam.entry_idx_v1);
	PHL_INFO("[BACAM] ba_cam.band_sel = %d, ba_cam.uid_value = %d, ba_cam.std_entry_en = %d\n",
			 ba_cam.band_sel,
			 ba_cam.uid_value,
			 ba_cam.std_entry_en);

	hal_status = rtw_hal_bacam_cfg(hal_info, &ba_cam);

	if (RTW_HAL_STATUS_FAILURE == hal_status) {
		PHL_WARN("rtw_hal_bacam_cfg fail 0x%08X\n", hal_status);

	}

	FUNCOUT();
	return hal_status;
}

enum rtw_hal_status
rtw_hal_start_ba_session(void *hal, struct rtw_phl_stainfo_t *sta,
                         u8 dialog_token, u16 timeout,
                         u16 start_seq_num, u16 ba_policy,
                         u16 tid, u16 buf_size)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	struct rtw_phl_com_t *phl_com = hal_info->phl_com;
	struct rtw_hal_com_t *hal_com = hal_info->hal_com;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	struct hal_spec_t *hal_spec = phl_get_ic_spec(phl_com);
	u8 max_std_entry_num = hal_spec->max_std_entry_num;
	u8 band_idx = sta->rlink->hw_band;
	u8 entry_idx = 0;

	/* Update existing standard entry */
	for (entry_idx = 0; entry_idx < max_std_entry_num; entry_idx++) {
		if (hal_com->ba_ctl.used_map[entry_idx]
		    && sta->macid == hal_com->ba_ctl.mac_id[entry_idx]
		    && (u8)tid == hal_com->ba_ctl.tid[entry_idx]) {
			PHL_INFO("Update existing standard entry(macid=%d, tid=%d)\n",
			         sta->macid, tid);
			hal_status = _hal_update_ba_cam(hal_info, 1, sta->macid, dialog_token,
			                                timeout, start_seq_num, ba_policy, tid,
			                                buf_size, entry_idx, band_idx, 0, true);
			goto out;
		}
	}

	if (hal_com->ba_ctl.count == max_std_entry_num) {
		/*
		 * Transfer existing standard entry to temp entry
		 * when TID is 0(AC_BE) or 5(AC_VI)
		 */
		if (tid == 0 || tid == 5) {
			for (entry_idx = 0; entry_idx < max_std_entry_num; entry_idx++) {
				if (hal_com->ba_ctl.tid[entry_idx] != 0
				    && hal_com->ba_ctl.tid[entry_idx] != 5) {
					PHL_INFO("Transfer existing standard entry to temp entry \
					         (entry_idx=%d, macid=%d, tid=%d).\n",
					         entry_idx, hal_com->ba_ctl.mac_id[entry_idx],
					         hal_com->ba_ctl.tid[entry_idx]);
					hal_status = _hal_update_ba_cam(hal_info, 0, 0, 0, 0,
					                                0, 0, 0, 0, entry_idx, HW_BAND_0, 0, false);
					if (hal_status == RTW_HAL_STATUS_SUCCESS) {
						hal_com->ba_ctl.used_map[entry_idx] = 0;
						hal_com->ba_ctl.tid[entry_idx] = 0xff;
						hal_com->ba_ctl.mac_id[entry_idx] = 0xffff;
						hal_com->ba_ctl.count--;
						break;
					}
				}
			}
		} else {
			PHL_INFO("No available standard entry for tid(%d)\n", tid);
			goto out;
		}
	}

	for (entry_idx = 0; entry_idx < max_std_entry_num; entry_idx++) {
		if (!hal_com->ba_ctl.used_map[entry_idx])
			break;
	}
	if (entry_idx == max_std_entry_num) {
		PHL_WARN("No avail standard entry found but count is(%d)\n",
			hal_com->ba_ctl.count);
		goto out;
	}
	hal_status = _hal_update_ba_cam(hal_info, 1, sta->macid, dialog_token,
	                                timeout, start_seq_num, ba_policy, tid,
	                                buf_size, entry_idx, band_idx, 0, true);
	if (RTW_HAL_STATUS_SUCCESS != hal_status)
		goto out;

	hal_com->ba_ctl.used_map[entry_idx] = 1;
	hal_com->ba_ctl.tid[entry_idx] = (u8)tid;
	hal_com->ba_ctl.mac_id[entry_idx] = sta->macid;
	hal_com->ba_ctl.count++;
out:
	return hal_status;
}

enum rtw_hal_status
rtw_hal_stop_ba_session(void *hal, struct rtw_phl_stainfo_t *sta, u16 tid)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	struct rtw_phl_com_t *phl_com = hal_info->phl_com;
	struct rtw_hal_com_t *hal_com = hal_info->hal_com;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	struct hal_spec_t *hal_spec = phl_get_ic_spec(phl_com);
	u8 max_std_entry_num = hal_spec->max_std_entry_num;
	u8 entry_idx = 0;

	for (entry_idx = 0; entry_idx < max_std_entry_num; entry_idx++) {
		if (hal_com->ba_ctl.used_map[entry_idx]
		    && sta->macid == hal_com->ba_ctl.mac_id[entry_idx]
		    && (u8)tid == hal_com->ba_ctl.tid[entry_idx]) {
			hal_status = _hal_update_ba_cam(hal_info, 0, 0, 0, 0,
			                                0, 0, 0, 0, entry_idx, HW_BAND_0, 0, false);
			break;
		}
	}
	if (RTW_HAL_STATUS_SUCCESS != hal_status)
		goto out;
	hal_com->ba_ctl.used_map[entry_idx] = 0;
	hal_com->ba_ctl.tid[entry_idx] = 0xff;
	hal_com->ba_ctl.mac_id[entry_idx] = 0xffff;
	hal_com->ba_ctl.count--;
out:
	return hal_status;
}

enum rtw_hal_status
rtw_hal_init_tmp_entry(void *hal, u8 tmp_entry_num, u8 std_entry_num)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	u8 entry_idx = std_entry_num;
	u8 uid = 0, cnt = 0;
	u8 b0_tmp_num = tmp_entry_num;

#ifdef CONFIG_DBCC_SUPPORT
	u8 b1_tmp_num = 0;

	if (is_dbcc_sup(hal_info->phl_com)) {
		b1_tmp_num = tmp_entry_num / 2;
		b0_tmp_num = tmp_entry_num - b1_tmp_num;
		if (b1_tmp_num == 0) {
			PHL_ERR("%s: b1_tmp_num = 0, we can't init tmp entry for Band1. It may can't respond to AMPDU!\n",
				__FUNCTION__);
		}
	}
#endif /* CONFIG_DBCC_SUPPORT */

	uid = 0;
	for (cnt = 0; cnt < b0_tmp_num; cnt++) {
		hal_status = _hal_update_ba_cam(hal_info, 1, 0, 0, 0, 0,
		                                0, 0, 0, entry_idx, HW_BAND_0, uid, false);
		if (RTW_HAL_STATUS_SUCCESS != hal_status) {
			PHL_ERR("rtw_hal_init_tmp_entry fail!\n");
			break;
		}
		entry_idx++;
		uid++;
	}

#ifdef CONFIG_DBCC_SUPPORT
	uid = 0;
	for (cnt = 0; cnt < b1_tmp_num; cnt++) {
		hal_status = _hal_update_ba_cam(hal_info, 1, 0, 0, 0, 0,
		                                0, 0, 0, entry_idx, HW_BAND_1, uid, false);
		if (RTW_HAL_STATUS_SUCCESS != hal_status) {
			PHL_ERR("rtw_hal_init_tmp_entry fail!\n");
			break;
		}
		entry_idx++;
		uid++;
	}
#endif /* CONFIG_DBCC_SUPPORT */
	return hal_status;
}

enum rtw_hal_status
rtw_hal_stainfo_init(void *hal, struct rtw_phl_stainfo_t *sta)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	void *drv = hal_to_drvpriv(hal_info);

	sta->hal_sta = _os_mem_alloc(drv, sizeof(struct rtw_hal_stainfo_t));
	if (sta->hal_sta == NULL) {
		PHL_ERR("alloc hal_sta failed\n");
		goto error_exit;
	}

#if defined(CONFIG_PHL_RELEASE_RPT_ENABLE) || defined(CONFIG_PCI_HCI)
	/* alloc trx_stats */
	sta->hal_sta->trx_stat.wp_rpt_stats = _os_mem_alloc(drv,
		sizeof(struct rtw_wp_rpt_stats) * RTW_MAX_WP_RPT_AC_NUM(hal_info));

	if (sta->hal_sta->trx_stat.wp_rpt_stats == NULL) {
		PHL_ERR("alloc wp_rpt_stats failed\n");
		goto error_rpt_stats;
	}
#endif

	hal_status = rtw_hal_bb_stainfo_init(hal_info, sta);
	if (hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("alloc bb_stainfo failed\n");
		goto error_hsta_mem;
	}
	/* Init lock for tx statistics */
	_os_spinlock_init(drv, &sta->hal_sta->trx_stat.tx_sts_lock);
	/* Init STA RSSI Statistics */
	_hal_sta_rssi_init(sta);

	return hal_status;
error_hsta_mem :
#if defined(CONFIG_PHL_RELEASE_RPT_ENABLE) || defined(CONFIG_PCI_HCI)
	if (sta->hal_sta->trx_stat.wp_rpt_stats) {
		_os_mem_free(drv, sta->hal_sta->trx_stat.wp_rpt_stats,
			     sizeof(struct rtw_wp_rpt_stats) * RTW_MAX_WP_RPT_AC_NUM(hal_info));
		sta->hal_sta->trx_stat.wp_rpt_stats = NULL;
	}

error_rpt_stats :
#endif
	if (sta->hal_sta) {
		_os_mem_free(drv, sta->hal_sta,
				sizeof(struct rtw_hal_stainfo_t));
		sta->hal_sta = NULL;
	}
error_exit :
	return hal_status;
}

enum rtw_hal_status
rtw_hal_stainfo_deinit(void *hal, struct rtw_phl_stainfo_t *sta)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	void *drv = hal_to_drvpriv(hal_info);

	if (sta->hal_sta) {
		/* Free lock for tx statistics */
		_os_spinlock_free(drv, &sta->hal_sta->trx_stat.tx_sts_lock);

#if defined(CONFIG_PHL_RELEASE_RPT_ENABLE) || defined(CONFIG_PCI_HCI)
		if (sta->hal_sta->trx_stat.wp_rpt_stats) {
			_os_mem_free(drv, sta->hal_sta->trx_stat.wp_rpt_stats,
				     sizeof(struct rtw_wp_rpt_stats) * RTW_MAX_WP_RPT_AC_NUM(hal_info));
			sta->hal_sta->trx_stat.wp_rpt_stats = NULL;
		}
#endif
		hal_status = rtw_hal_bb_stainfo_deinit(hal_info, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS)
			PHL_ERR("bb_stainfo deinit failed\n");

		_os_mem_free(drv, sta->hal_sta,
				sizeof(struct rtw_hal_stainfo_t));
		sta->hal_sta = NULL;
	}

	return hal_status;
}
static void _hal_sta_set_default_value(struct hal_info_t *hal_info,
        struct rtw_phl_stainfo_t *sta)
{
	sta->hal_sta->ra_info.ra_registered = false;
}

enum rtw_hal_status
rtw_hal_set_dctrl_tbl_seciv(void *hal,
				struct rtw_phl_stainfo_t *sta, u64 iv)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status sts = RTW_HAL_STATUS_FAILURE;
	struct mac_ax_dctl_info dctrl = {0}, dctrl_mask = {0};

	if (NULL == sta)
		goto out;

	dctrl.aes_iv_l = (u16)(iv & 0xffffL);
	dctrl.aes_iv_h = (u32)(iv >> 16) & 0xffffffffL;

	dctrl_mask.aes_iv_l = 0xffffL;
	dctrl_mask.aes_iv_h = 0xffffffffL;

	sts = rtw_hal_dmc_tbl_cfg(hal_info, &dctrl ,&dctrl_mask, sta->macid);

out:
	return sts;
}

enum rtw_hal_status
rtw_hal_add_sta_entry(void *hal, struct rtw_phl_stainfo_t *sta)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;

	_hal_sta_set_default_value(hal_info, sta);

	/*add mac address-cam*/
	if (rtw_hal_mac_addr_cam_add_entry(hal_info, sta) !=
					RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("rtw_hal_mac_addr_cam_add_entry failed\n");
		goto _exit;
	}

	/*update default cmac table*/
	if (_hal_set_default_cctrl_tbl(hal_info, sta) !=
					RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("_hal_set_default_cctrl_tbl failed\n");
		/* goto _exit; */ /* shall be unmark after header FW is ready */
	}

	if (_hal_update_dctrl_tbl(hal_info, sta) !=
					RTW_HAL_STATUS_SUCCESS) {
		PHL_WARN("_hal_set_default_dctrl_tbl failed\n");
		/* goto _exit; */
	}

	/*add bb stainfo*/
	if (rtw_hal_bb_stainfo_add(hal_info, sta) !=
					RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("rtw_hal_bb_stainfo_add failed\n");
		goto _err_bbsta_add;
	}
	return RTW_HAL_STATUS_SUCCESS;

_err_bbsta_add:
	rtw_hal_mac_addr_cam_del_entry(hal_info, sta);
_exit:
	return RTW_HAL_STATUS_FAILURE;
}

#define WAIT_DROP_PKT_TIMEOUT 300
void
rtw_hal_disconnect_drop_all_pkt(void *hal, struct rtw_phl_stainfo_t *sta)
{
	struct hal_info_t *hal_i = (struct hal_info_t *)hal;

#ifdef CONFIG_PCI_HCI
	struct rtw_wp_rpt_stats *rpt_stats =
		(struct rtw_wp_rpt_stats *)sta->hal_sta->trx_stat.wp_rpt_stats;
	u32 start_time = _os_get_cur_time_ms();
	u16 cnt = 0;

	while (true) {
		cnt++;
		rtw_hal_mac_data_drop_once(hal_i->hal_com, sta);
		if (0 == rpt_stats->busy_cnt) {
			PHL_INFO("%s: rpt_stats->busy_cnt == 0, loop cnt(%d)\n",
				__func__, cnt);
			break;
		}
		if (phl_get_passing_time_ms(start_time) > WAIT_DROP_PKT_TIMEOUT) {
			PHL_ERR("%s: Fail, wait time > (%d), busy_cnt(%d)\n",
				__func__, WAIT_DROP_PKT_TIMEOUT,
				rpt_stats->busy_cnt);
			break;
		}
		_os_sleep_ms(hal_to_drvpriv(hal_i), 5);
	}
#else
	/* todo: check empty for usb, sdio */
	rtw_hal_mac_data_drop_once(hal_i->hal_com, sta);
#endif
}

enum rtw_hal_status
rtw_hal_restore_sta_entry(struct rtw_phl_com_t* phl_com, void *hal,
                          struct rtw_phl_stainfo_t *sta, bool is_connect)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	enum phl_upd_mode mode = PHL_UPD_STA_CON_DISCONN;

	hal_status = rtw_hal_mac_addr_cam_change_entry(hal_info, sta, PHL_UPD_ROLE_FW_RESTORE, is_connect);
	if (hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("rtw_hal_mac_addr_cam_change_entry failed\n");
		return hal_status;
	}

	/* update cmac table */
	if (RTW_HAL_STATUS_SUCCESS != _hal_update_cctrl_tbl(hal_info, sta))
		PHL_WARN("_hal_update_cctrl_tbl failed\n");

	/*update dmac table*/
	if (RTW_HAL_STATUS_SUCCESS != _hal_update_dctrl_tbl(hal_info, sta))
		PHL_WARN("_hal_update_dctrl_tbl failed\n");

	/*change mac address-cam & mac_h2c_join_info*/
	hal_status = rtw_hal_mac_addr_cam_change_entry(hal_info, sta, mode, is_connect);
	if (hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("rtw_hal_mac_addr_cam_change_entry failed\n");
	}

	if (is_connect) {
		rtw_phl_pkt_ofld_null_request(phl_com, sta, NULL);

		hal_status = rtw_hal_cfg_tx_ampdu(hal, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS) {
			PHL_ERR("rtw_hal_cfg_tx_ampdu failed\n");
		}

		if (RTW_HAL_STATUS_SUCCESS != _hal_bfee_init(hal_info, sta)) {
			PHL_ERR("_hal_bfee_init Fail!\n");
		}

		if (sta->hal_sta->rssi_stat.assoc_rssi == 0
                #ifdef CONFIG_PHL_TDLS
			/* There is no association frame for TDLS connection */
			&& sta->wrole->type != PHL_RTYPE_TDLS
                #endif
		) {
			PHL_ERR("%s macid:%d assoc_rssi == 0\n", __func__, sta->macid);
			_os_warn_on(1);
		}

		hal_status = rtw_hal_bb_upt_ramask(hal_info, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS)
			PHL_ERR("rtw_hal_bb_upt_ramask failed\n");

		hal_status = rtw_hal_bb_ra_register(hal_info, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS)
			PHL_ERR("rtw_hal_bb_ra_register failed\n");

		if (sta->wmode & WLAN_MD_11AX) {
			rtw_hal_bb_set_sta_id(hal_info, sta->aid, sta->rlink->hw_band);
			rtw_hal_bb_set_bss_color(hal_info, sta->asoc_cap.bsscolor,
				sta->rlink->hw_band);
			rtw_hal_bb_set_tb_pwr_ofst(hal_info, 0, sta->rlink->hw_band);
		}
		/* reset rssi stat value */
		sta->hal_sta->rssi_stat.ma_rssi_mgnt = 0;
	} else {
		rtw_phl_pkt_ofld_reset_entry(phl_com, sta->macid);

		hal_status = rtw_hal_bb_ra_deregister(hal_info, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS)
			PHL_ERR("rtw_hal_bb_ra_deregister failed\n");

		rtw_hal_disconnect_drop_all_pkt(hal_info, sta);
		/* reset drv rssi_stat */
		_hal_sta_rssi_init(sta);
		_hal_sta_set_default_value(hal_info, sta);
	}
	/* reset bb rssi_stat */
	rtw_hal_bb_media_status_update(hal_info, sta, is_connect);

	return hal_status;
}

enum rtw_hal_status
rtw_hal_update_sta_entry(struct rtw_phl_com_t* phl_com, void *hal,
                         struct rtw_phl_stainfo_t *sta, bool is_connect)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	enum phl_upd_mode mode = PHL_UPD_STA_CON_DISCONN;

	/* update cmac table */
	if (RTW_HAL_STATUS_SUCCESS != _hal_update_cctrl_tbl(hal_info, sta))
		PHL_WARN("_hal_update_cctrl_tbl failed\n");

	/* update dmac table */
	if (RTW_HAL_STATUS_SUCCESS != _hal_update_dctrl_tbl(hal_info, sta))
		PHL_WARN("_hal_update_dctrl_tbl failed\n");

	/* change mac address-cam & mac_h2c_join_info */
	hal_status = rtw_hal_mac_addr_cam_change_entry(hal_info, sta, mode, is_connect);
	if (hal_status != RTW_HAL_STATUS_SUCCESS) {
		PHL_ERR("rtw_hal_cfg_tx_ampdu failed\n");
	}

	if (is_connect) {
		if (rtw_phl_role_is_client_category(sta->wrole)) {
			rtw_hal_mac_tbtt_tuning_cfg(hal_info,
						    sta->rlink->hw_band,
						    sta->rlink->hw_port,
						    0);
		}
		rtw_phl_pkt_ofld_null_request(phl_com, sta, NULL);

		hal_status = rtw_hal_cfg_tx_ampdu(hal, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS) {
			PHL_ERR("rtw_hal_cfg_tx_ampdu failed\n");
		}

		if (RTW_HAL_STATUS_SUCCESS != _hal_bfee_init(hal_info, sta)) {
			PHL_ERR("_hal_bfee_init Fail!\n");
		}

		if (sta->hal_sta->rssi_stat.assoc_rssi == 0
                #ifdef CONFIG_PHL_TDLS
			/* There is no association frame for TDLS connection */
			&& sta->wrole->type != PHL_RTYPE_TDLS
                #endif
		) {
			PHL_ERR("%s macid:%d assoc_rssi == 0\n", __func__, sta->macid);
			_os_warn_on(1);
		}

		hal_status = rtw_hal_bb_upt_ramask(hal_info, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS)
			PHL_ERR("rtw_hal_bb_upt_ramask failed\n");

		hal_status = rtw_hal_bb_ra_register(hal_info, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS)
			PHL_ERR("rtw_hal_bb_ra_register failed\n");
		hal_info->hal_com->assoc_sta_cnt++;
		hal_info->hal_com->band[sta->rlink->hw_band].assoc_sta_cnt++;

		if (sta->wmode & WLAN_MD_11AX) {
			rtw_hal_bb_set_sta_id(hal_info, sta->aid, sta->rlink->hw_band);
			rtw_hal_bb_set_bss_color(hal_info, sta->asoc_cap.bsscolor,
				sta->rlink->hw_band);
			rtw_hal_bb_set_tb_pwr_ofst(hal_info, 0, sta->rlink->hw_band);
		}
		/* reset rssi stat value */
		sta->hal_sta->rssi_stat.ma_rssi_mgnt = 0;
	} else {
		rtw_phl_pkt_ofld_reset_entry(phl_com, sta->macid);

		hal_status = rtw_hal_bb_ra_deregister(hal_info, sta);
		if (hal_status != RTW_HAL_STATUS_SUCCESS)
			PHL_ERR("rtw_hal_bb_ra_deregister failed\n");

		hal_info->hal_com->assoc_sta_cnt--;
		hal_info->hal_com->band[sta->rlink->hw_band].assoc_sta_cnt--;
		rtw_hal_disconnect_drop_all_pkt(hal_info, sta);
		/* reset drv rssi_stat */
		_hal_sta_rssi_init(sta);
		_hal_sta_set_default_value(hal_info, sta);
	}
	/* reset bb rssi_stat */
	rtw_hal_bb_media_status_update(hal_info, sta, is_connect);
	PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: hal_status(%d), macid(0x%X), is_connect(%d)\n",
		__FUNCTION__, hal_status, sta->macid , is_connect);
	return hal_status;
}

enum rtw_hal_status
rtw_hal_change_sta_entry(void *hal, struct rtw_phl_stainfo_t *sta,
						enum phl_upd_mode mode)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;
	bool is_connect = false;
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
	PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: sta->macid(0x%X), mode(%d)\n",
		__FUNCTION__, sta->macid , mode);
	/* update cmac table */
	if (RTW_HAL_STATUS_SUCCESS != _hal_update_cctrl_tbl(hal_info, sta))
		PHL_WARN("_hal_update_cctrl_tbl failed\n");

	/* update dmac table */
	if (RTW_HAL_STATUS_SUCCESS != _hal_update_dctrl_tbl(hal_info, sta))
		PHL_WARN("_hal_update_dctrl_tbl failed\n");

	/* change mac address-cam & mac_h2c_join_info */
	is_connect = (sta->rlink->mstate == MLME_LINKED) ? true : false;
	hal_status = rtw_hal_mac_addr_cam_change_entry(hal_info, sta, mode, is_connect);
	if (hal_status != RTW_HAL_STATUS_SUCCESS)
		PHL_ERR("rtw_hal_mac_addr_cam_change_entry failed\n");

	hal_status = rtw_hal_bb_ra_update(hal_info, sta);
	if (hal_status != RTW_HAL_STATUS_SUCCESS)
		PHL_ERR("rtw_hal_bb_ra_update failed\n");
#ifdef DBG_DBCC_MONITOR_TIME
	PHL_FUNC_MON_END(hal_info->phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
	return hal_status;
}

enum rtw_hal_status
rtw_hal_del_sta_entry(void *hal, struct rtw_phl_stainfo_t *sta)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status = RTW_HAL_STATUS_FAILURE;

	_hal_sta_set_default_value(hal_info, sta);

	hal_status = rtw_hal_mac_addr_cam_del_entry(hal_info, sta);
	if (hal_status != RTW_HAL_STATUS_SUCCESS)
		PHL_ERR("mac_addr_cam_del_entry failed\n");

	hal_status = rtw_hal_bb_stainfo_delete(hal_info, sta);
	if (hal_status != RTW_HAL_STATUS_SUCCESS)
		PHL_ERR("bb_stainfo deinit failed\n");

	return hal_status;
}

u8 rtw_hal_get_sta_rssi(struct rtw_phl_stainfo_t *sta)
{
	u8 rssi = (sta->hal_sta->rssi_stat.rssi >> 1);

	return rssi;
}

u8 rtw_hal_get_sta_rssi_bcn(struct rtw_phl_stainfo_t *sta)
{
	u8 rssi = (sta->hal_sta->rssi_stat.rssi_bcn >> 1);

	return rssi;
}

bool rtw_hal_is_sta_linked(void *hal, struct rtw_phl_stainfo_t *sta)
{
	return (sta->hal_sta->ra_info.ra_registered == true) ? true : false;
}

enum rtw_hal_status
rtw_hal_set_edca(void *hal,
                 struct rtw_wifi_role_link_t *rlink,
                 u8 ac,
                 u32 edca)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hal_status;

	hal_status = rtw_hal_mac_set_edca(hal_info->hal_com, rlink->hw_band,
					  rlink->hw_wmm, ac, edca);

	return hal_status;
}

enum rtw_hal_status
rtw_hal_cfg_tx_amsdu(void *hal,
		     u8 macid,
		     u8 enable,
		     u8 amsdu_max_len,
		     u8 qos_field_h,
		     u8 qos_field_h_en,
		     u8 mhdr_len,
		     u8 vlan_tag_valid)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE;

	/* set mac hdr length / QoS content */
	hsts = rtw_hal_mac_hdr_conv_tx_macid_en(hal_info,
						macid, qos_field_h,
						qos_field_h_en,
						mhdr_len,
						vlan_tag_valid);
	if (RTW_HAL_STATUS_SUCCESS != hsts) {
		PHL_ERR("rtw_hal_mac_hdr_conv_tx_macid_en failed, hsts = %d\n", hsts);
		goto out;
	}

	/* set HWAMSDU max length */
	hsts = rtw_hal_mac_hwamsdu_max_len(hal_info, macid, amsdu_max_len);
	if (RTW_HAL_STATUS_SUCCESS != hsts) {
		PHL_ERR("rtw_hal_mac_hwamsdu_max_len failed, hsts = %d\n", hsts);
		goto out;
	}

	/* enable HWAMSDU by macid */
	hsts = rtw_hal_mac_hwamsdu_macid_en(hal_info, macid, enable);
	if (RTW_HAL_STATUS_SUCCESS != hsts) {
		PHL_ERR("rtw_hal_mac_hwamsdu_macid_en failed, hsts = %d\n", hsts);
		goto out;
	}

	/* Could add more halmac ops and input parameter in this function */

out:
	return hsts;
}


enum rtw_hal_status
rtw_hal_set_sta_rx_sts(struct rtw_phl_stainfo_t *sta, u8 rst,
									struct rtw_r_meta_data *meta)
{
	if (rst) {
		sta->hal_sta->trx_stat.rx_ok_cnt = 0;
		sta->hal_sta->trx_stat.rx_err_cnt = 0;
	} else {
		if (meta->crc32 || meta->icverr)
			sta->hal_sta->trx_stat.rx_err_cnt++;
		else
			sta->hal_sta->trx_stat.rx_ok_cnt++;

		sta->hal_sta->trx_stat.rx_bw = meta->bw;
		sta->hal_sta->trx_stat.rx_rate = meta->rx_rate;
		sta->hal_sta->trx_stat.rx_gi_ltf = meta->rx_gi_ltf;
	}
	/* TODO: rx_rate_plurality */
	return RTW_HAL_STATUS_SUCCESS;
}

enum rtw_hal_status
rtw_hal_query_rainfo(void *hal, struct rtw_hal_stainfo_t *hal_sta,
		     struct rtw_phl_rainfo *phl_rainfo)
{
	enum rtw_hal_status hal_sts = RTW_HAL_STATUS_FAILURE;

	hal_sts = rtw_hal_bb_query_rainfo(hal, hal_sta, phl_rainfo);


	return hal_sts;
}

/**
 * rtw_hal_query_txsts_rpt() - get txok and tx retry info
 * @hal:		struct hal_info_t *
 * @macid:		indicate the first macid that you want to query.
 * Return rtw_hal_bb_query_txsts_rpt's return value in enum rtw_hal_status type.
 */
enum rtw_hal_status
rtw_hal_query_txsts_rpt(void *hal, u16 macid)
{
	struct hal_info_t *hal_info = (struct hal_info_t *)hal;
	/*get tx ok and tx retry statistics*/
	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_bb_query_txsts_rpt(hal_info, macid, 0xFFFF))
		return RTW_HAL_STATUS_FAILURE;
	else
		return RTW_HAL_STATUS_SUCCESS;
}

bool
rtw_hal_check_sta_has_busy_wp(struct rtw_phl_stainfo_t *sta)
{
#ifdef CONFIG_PCI_HCI
	struct rtw_wp_rpt_stats *rpt_stats = sta->hal_sta->trx_stat.wp_rpt_stats;
	return (rpt_stats->busy_cnt) ? true : false;
#else
	/*
	* TODO: USB/SDIO not implement busy wp cnt statistic yet,
	* so return false to avoid affect core-layer logic.
	*/
	return false;
#endif
}