/******************************************************************************
 *
 * 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 _PHL_MR_C_
#include "phl_headers.h"

#ifdef DBG_PHL_MR
void phl_mr_dump_role_info(const char *caller, const int line, bool show_caller,
	struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole)
{
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;

	if (show_caller)
		PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);

	PHL_INFO("\t[WROLE] RIDX:%d - MAC-Addr:%02x-%02x-%02x-%02x-%02x-%02x RTYPE:%d MSTS:%d\n",
		wrole->id, wrole->mac_addr[0], wrole->mac_addr[1], wrole->mac_addr[2],
		wrole->mac_addr[3], wrole->mac_addr[4], wrole->mac_addr[5],
		wrole->type, wrole->mstate);

	for (idx = 0; idx < wrole->rlink_num; idx++) {
		rlink = get_rlink(wrole, idx);

		PHL_INFO("\t[WROLE LINK] HW Band_idx:%d, Port_idx:%d, WMM_idx:%d\n", rlink->hw_band, rlink->hw_port, rlink->hw_wmm);

		if (rtw_phl_role_is_ap_category(wrole) || wrole->type == PHL_RTYPE_MESH) {
			#ifdef RTW_PHL_BCN
			PHL_INFO("\t[WROLE AP] BSSID:%02x-%02x-%02x-%02x-%02x-%02x\n",
				rlink->bcn_cmn.bssid[0], rlink->bcn_cmn.bssid[1], rlink->bcn_cmn.bssid[2],
				rlink->bcn_cmn.bssid[3], rlink->bcn_cmn.bssid[4], rlink->bcn_cmn.bssid[5]);
			PHL_INFO("\t[WROLE AP] BCN id:%d, interval:%d, rate:0x%04x, DTIM:%d\n",
				rlink->bcn_cmn.bcn_id, rlink->bcn_cmn.bcn_interval,
				rlink->bcn_cmn.bcn_rate, rlink->bcn_cmn.bcn_dtim);
			PHL_INFO("\t[WROLE AP] HW MBSSID idx:%d, MBID NUM:%d\n",
				rlink->hw_mbssid, rlink->mbid_num);
			#endif
		}
	}

	PHL_INFO("\n");
	if (show_caller)
		PHL_INFO("#################################\n");
}

void phl_mr_dump_rlink_info(const char *caller, const int line, bool show_caller,
	struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole,
	struct rtw_wifi_role_link_t *rlink)
{
	if (show_caller)
		PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);

	PHL_INFO("\t[RLINK] LIDX:%d - MAC-Addr:%02x-%02x-%02x-%02x-%02x-%02x RTYPE:%d MSTS:%d\n",
		rlink->id,
		rlink->mac_addr[0], rlink->mac_addr[1], rlink->mac_addr[2],
		rlink->mac_addr[3], rlink->mac_addr[4], rlink->mac_addr[5],
		wrole->type, rlink->mstate);

	PHL_INFO("\t[RLINK] HW Band_idx:%d, Port_idx:%d, WMM_idx:%d\n",
		rlink->hw_band, rlink->hw_port, rlink->hw_wmm);

	if (rtw_phl_role_is_ap_category(wrole) || wrole->type == PHL_RTYPE_MESH) {
		#ifdef RTW_PHL_BCN
		PHL_INFO("\t[RLINK AP] BSSID:%02x-%02x-%02x-%02x-%02x-%02x\n",
			rlink->bcn_cmn.bssid[0], rlink->bcn_cmn.bssid[1],
			rlink->bcn_cmn.bssid[2], rlink->bcn_cmn.bssid[3],
			rlink->bcn_cmn.bssid[4], rlink->bcn_cmn.bssid[5]);

		PHL_INFO("\t[RLINK AP] BCN id:%d, interval:%d, rate:0x%04x, DTIM:%d\n",
			rlink->bcn_cmn.bcn_id, rlink->bcn_cmn.bcn_interval,
			rlink->bcn_cmn.bcn_rate, rlink->bcn_cmn.bcn_dtim);

		PHL_INFO("\t[RLINK AP] HW MBSSID idx:%d, MBID NUM:%d\n",
			rlink->hw_mbssid, rlink->mbid_num);
		#endif
	}
	PHL_INFO("\n");
	if (show_caller)
		PHL_INFO("#################################\n");
}

void phl_mr_dump_chctx_info(const char *caller, const int line, bool show_caller,
	struct phl_info_t *phl_info, struct phl_queue *chan_ctx_queue, struct rtw_chan_ctx *chanctx)
{
	u8 role_num = 0;
	role_num = phl_chanctx_get_rnum(phl_info, chan_ctx_queue, chanctx);

	if (show_caller)
		PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);

	PHL_INFO("\t[CH-CTX] role num:%d map:0x%02x, DFS enable:%s\n",
		role_num, chanctx->role_map,
		(chanctx->dfs_enabled) ? "Y" : "N");
	PHL_DUMP_CHAN_DEF(&chanctx->chan_def);

	if (show_caller)
		PHL_INFO("#################################\n");
}

const char *const _opmod_str[] = {
	"MR_OP_NONE",
	"MR_OP_SWR",
	"MR_OP_SCC",
	"MR_OP_MCC",
	"MR_OP_DBCC",
	"MR_OP_NON"
};
#define _get_opmod_str(opmod) (((opmod) >= MR_OP_MAX) ? _opmod_str[MR_OP_MAX] : _opmod_str[(opmod)])


void phl_dump_cc_band_map(struct phl_info_t *phl_info, u16 cc_band_map)
{
	PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\t chctx_band -");
	if (cc_band_map == 0)
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_NON");
	if (cc_band_map & BIT(CC_BAND_24G))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_24G");
	if (cc_band_map & BIT(CC_BAND_5G_B1))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B1");
	if (cc_band_map & BIT(CC_BAND_5G_B2))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B2");
	if (cc_band_map & BIT(CC_BAND_5G_B3))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B3");
	if (cc_band_map & BIT(CC_BAND_5G_B4))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B4");
	if (cc_band_map & BIT(CC_BAND_6G_U5))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U5");
	if (cc_band_map & BIT(CC_BAND_6G_U6))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U6");
	if (cc_band_map & BIT(CC_BAND_6G_U7))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U7");
	if (cc_band_map & BIT(CC_BAND_6G_U8))
		PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U8");

	PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
}

void phl_mr_dump_band_info(const char *caller, const int line, bool show_caller,
	struct phl_info_t *phl_info, struct hw_band_ctl_t *band_ctrl)
{
	u8 role_num = 0;
	int chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);

	role_num = phl_mr_get_role_num(phl_info, band_ctrl);

	if (show_caller)
		PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);

	PHL_INFO("\t[BAND-%d] op_mode:%s port map:0x%02x, role num:%d map:0x%02x\n",
		band_ctrl->id, _get_opmod_str(band_ctrl->op_mode),
		band_ctrl->port_map, role_num, band_ctrl->role_map);

	/*dump mr_info*/
	PHL_INFO("\t[BAND-%d] sta_num:%d, ld_sta_num:%d, lg_sta_num:%d\n",
		band_ctrl->id, band_ctrl->cur_info.sta_num,
		band_ctrl->cur_info.ld_sta_num, band_ctrl->cur_info.lg_sta_num);
	PHL_INFO("\t[BAND-%d] ap_num:%d, ld_ap_num:%d\n",
		band_ctrl->id, band_ctrl->cur_info.ap_num, band_ctrl->cur_info.ld_ap_num);

	PHL_INFO("\t[BAND-%d] chan_ctx num:%d, cc_band_map:0x%04x\n",
		band_ctrl->id, chanctx_num, band_ctrl->chctx_band_map);
	phl_dump_cc_band_map(phl_info, band_ctrl->chctx_band_map);

	if (chanctx_num) {
		struct rtw_chan_ctx *chanctx = NULL;
		_os_list *chctx_list = &band_ctrl->chan_ctx_queue.queue;
		void *drv = phl_to_drvpriv(phl_info);

		_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
		phl_list_for_loop(chanctx, struct rtw_chan_ctx, chctx_list, list) {
			PHL_DUMP_CHAN_CTX(phl_info, &band_ctrl->chan_ctx_queue, chanctx);
		}
		_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
	}
	PHL_INFO("\n");
	if (show_caller)
		PHL_INFO("#################################\n");
}

void phl_mr_dump_info(const char *caller, const int line, bool show_caller,
	struct phl_info_t *phl_info)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct rtw_wifi_role_t *wrole;
	u8 i;
	u8 role_num = 0;

	if (show_caller)
		PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);

	for (i = 0; i < MAX_WIFI_ROLE_NUMBER; i++) {
		if (mr_ctl->role_map & BIT(i))
			role_num++;
	}

	PHL_INFO("[MR] MAX wrole num:%d, created num:%d map:0x%02x\n",
			MAX_WIFI_ROLE_NUMBER, role_num, mr_ctl->role_map);
	PHL_INFO("[MR] is_db:%s, cck_phyidx:%d\n",
				(mr_ctl->is_db) ? "Y" : "N",
				mr_ctl->cck_phyidx);

	for (i = 0; i < MAX_WIFI_ROLE_NUMBER; i++) {
		if (mr_ctl->role_map & BIT(i)) {
			wrole = phl_get_wrole_by_ridx(phl_info, i);
			PHL_DUMP_ROLE(phl_info, wrole);
		}
	}

	for (i = 0; i < MAX_BAND_NUM; i++)
		PHL_DUMP_BAND_CTL(phl_info, &mr_ctl->band_ctrl[i]);

	if (show_caller)
		PHL_INFO("#################################\n");
}

void phl_mr_dump_cur_chandef(const char *caller, const int line, bool show_caller,
		struct phl_info_t *phl_info, struct rtw_wifi_role_t *wifi_role)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct rtw_chan_def *chan_def = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;

	if (show_caller)
		PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);

	for (idx = 0; idx < wifi_role->rlink_num; idx++) {
		rlink = get_rlink(wifi_role, idx);

		if (rlink->chanctx) {
			chan_def = &rlink->chanctx->chan_def;
			PHL_INFO("==== MR Chan-def ===\n");
			PHL_DUMP_CHAN_DEF(chan_def);
		}

		chan_def = &rlink->chandef;
		PHL_INFO("==== WR-%d RLINK-%d Chan-def ===\n", wifi_role->id, rlink->id);
		PHL_DUMP_CHAN_DEF(chan_def);

		chan_def = &mr_ctl->hal_com->band[rlink->hw_band].cur_chandef;
		PHL_INFO("==== HAL Band-%d Chan-def ===\n", rlink->hw_band);
		PHL_DUMP_CHAN_DEF(chan_def);
	}

	if (show_caller)
		PHL_INFO("#################################\n");
}

#ifdef	PHL_MR_PROC_CMD
void rtw_phl_mr_dump_info(void *phl, bool show_caller)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	if (show_caller)
		PHL_DUMP_MR(phl_info);
	else
		PHL_DUMP_MR_EX(phl_info);
}
void rtw_phl_mr_dump_band_ctl(void *phl, bool show_caller)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	int i;

	for (i = 0; i < MAX_BAND_NUM; i++) {
		if (show_caller)
			PHL_DUMP_BAND_CTL(phl_info, &mr_ctl->band_ctrl[i]);
		else
			PHL_DUMP_BAND_CTL_EX(phl_info, &mr_ctl->band_ctrl[i]);

	}
}
#endif /*PHL_MR_PROC_CMD*/
#endif /*DBG_PHL_MR*/

static struct rtw_wifi_role_t *_search_ld_sta_wrole(struct rtw_wifi_role_t *wrole,
                                                    struct rtw_wifi_role_link_t *rlink,
                                                    u8 exclude_self)
{
	u8 ridx = 0;
	struct rtw_phl_com_t *phl_com = wrole->phl_com;
	struct rtw_chan_ctx *chanctx = rlink->chanctx;
	struct rtw_wifi_role_t *wr = NULL;

	if (chanctx == NULL) {
		PHL_ERR("%s wifi role(%d) chan ctx is null\n", __func__, wrole->id);
		goto exit;
	}

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (chanctx->role_map & BIT(ridx)) {
			wr = &phl_com->wifi_roles[ridx];
			if (wr) {
				if ((exclude_self) && (wr == wrole))
					continue;
				if (rtw_phl_role_is_client_category(wr))
					break;
			}
		}
	}

	if (wr)
		PHL_INFO("search Linked STA wifi role (%d)\n", wr->id);
exit:
	return wr;
}

void rtw_phl_mr_dump_cur_chandef(void *phl, struct rtw_wifi_role_t *wrole)
{
	#ifdef	PHL_MR_PROC_CMD
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	PHL_DUMP_CUR_CHANDEF(phl_info, wrole);
	#endif
}


static enum rtw_phl_status
_phl_band_ctrl_init(struct phl_info_t *phl_info)
{
	void *drv = phl_to_drvpriv(phl_info);
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	struct hw_band_ctl_t *band_ctrl;
	u8 band_idx = 0;

	for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
		band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
		band_ctrl->id = band_idx;
		_os_spinlock_init(drv, &(band_ctrl->lock));
		pq_init(drv, &band_ctrl->chan_ctx_queue);
		band_ctrl->op_mode = MR_OP_NONE;
		band_ctrl->tsf_sync_port = HW_PORT_MAX;
		band_ctrl->port_map = 0;
		band_ctrl->role_map = 0;
		band_ctrl->chctx_band_map = 0;
		#ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP
		band_ctrl->mbssid_cnt = 0;
		band_ctrl->mbssid_map = 0;
		#endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */
	}

	return RTW_PHL_STATUS_SUCCESS;
}

#ifdef RTW_WKARD_ISSUE_NULL_SLEEP_PROTECTION
#define ISSUE_NULL_TIME 50
#endif

struct mr_scan_chctx {
	struct rtw_chan_def *chandef;
	u8 role_map_ps;/*STA, MESH*/
	u8 role_map_ap;
};

static inline enum rtw_phl_status
_phl_wr_offch_bcn_hdl(struct phl_info_t *phl_info,
		 u8 hw_band,
		 struct rtw_wifi_role_t *wr,
		 bool off_ch
)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
	enum rtw_hal_status hsts = RTW_HAL_STATUS_SUCCESS;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;

	for (idx = 0; idx < wr->rlink_num; idx++) {
		rlink = get_rlink(wr, idx);

		if (rlink->hw_band != hw_band)
			continue;

		hsts = rtw_hal_beacon_stop(phl_info->hal, rlink,
			RLINK_BCN_STOP_RSON_DEFAULT, off_ch);
		if (hsts != RTW_HAL_STATUS_SUCCESS) {
			PHL_ERR("%s %s beacon failed\n", __func__,
				(off_ch) ? "stop" : "resume");
			psts = RTW_PHL_STATUS_FAILURE;
		}
	}
	return psts;
}

static inline enum rtw_phl_status
_phl_wr_offch_ps_hdl(struct phl_info_t *phl_info,
		 u8 hw_band,
		 struct rtw_wifi_role_t *wr,
		 bool off_ch,
		 void *obj_priv,
		 u8 module_id,
		 bool (*issue_null_data)(void *priv, u8 ridx, u8 lidx, bool ps,
		                         u8 module_id))
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;

	for (idx = 0; idx < wr->rlink_num; idx++) {
		rlink = get_rlink(wr, idx);

		if (rlink->hw_band != hw_band)
			continue;

		if (((TEST_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN)) && off_ch) ||
		    ((!TEST_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN)) && !off_ch))
			continue;
		if (issue_null_data(obj_priv, wr->id, idx, off_ch, module_id)
		                    == _SUCCESS) {
			if (off_ch) {
				SET_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN);
				#ifdef RTW_WKARD_ISSUE_NULL_SLEEP_PROTECTION
				_os_sleep_ms(phl_to_drvpriv(phl_info), ISSUE_NULL_TIME);
				#endif
			} else {
				CLEAR_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN);
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				"%s: wr(%d) rlink(%d)- hw_band(%d) off_ch(%d)\n",
				__func__, wr->id, rlink->id, hw_band, off_ch);

		} else {
			PHL_ERR("WR-ID:%d, RLINK-ID: %d issue null_data failed\n", wr->id, idx);
			_os_warn_on(1);
			psts = RTW_PHL_STATUS_FAILURE;
			break;
		}
	}

	return psts;
}

#ifdef CONFIG_MR_SUPPORT
static enum rtw_phl_status
_phl_mr_offch_hdl(struct phl_info_t *phl_info,
		 u8 hw_band,
		 bool off_ch,
		 void *obj_priv,
		 u8 module_id,
		 bool (*issue_null_data)(void *priv, u8 ridx, u8 lidx, bool ps,
		                         u8 module_id))
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
	void *drv = phl_to_drvpriv(phl_info);
	struct rtw_chan_ctx *chanctx = NULL;
	struct rtw_wifi_role_t *wr = NULL;
	struct mr_scan_chctx mctx = {0};
	int ctx_num = 0;
	u8 ridx = 0;
	u8 cur_ch = rtw_hal_get_cur_ch(phl_info->hal, hw_band);
	bool found = false;
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */

	if (issue_null_data == NULL) {
		PHL_ERR("%s issue null_data function not found\n", __func__);
		_os_warn_on(1);
		goto _exit;
	}

	ctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);

	if (ctx_num == 0) {
		PHL_DBG("ctx_num == 0!\n");
		goto _exit;
	}

	_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
	phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {
		/* Find the chanctx same as the current channel */
		if(chanctx->chan_def.chan != cur_ch)
			continue;

		PHL_DBG("%s current chanctx found!\n", __FUNCTION__);
		mctx.chandef = &chanctx->chan_def;
		found = true;

		for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
			if (chanctx->role_map & BIT(ridx)) {
				wr = &phl_com->wifi_roles[ridx];
				if(wr->active != true || wr->mstate != MLME_LINKED)
					continue;
				if (rtw_phl_role_is_client_category(wr)) {
					mctx.role_map_ps |= BIT(ridx);
				} else if (rtw_phl_role_is_ap_category(wr) ||
					wr->type == PHL_RTYPE_MESH) {
					mctx.role_map_ap |= BIT(ridx);
				}
			}
		}
	}
	_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);

	if (!found) {
		PHL_DBG("No chanctx is the same as current channel!\n");
		goto _exit;
	}

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if ((mctx.role_map_ap) && (mctx.role_map_ap & BIT(ridx))) {
			wr = &phl_com->wifi_roles[ridx];
			psts = _phl_wr_offch_bcn_hdl(phl_info, hw_band, wr, off_ch);
			if (psts == RTW_PHL_STATUS_FAILURE) {
				PHL_ERR("%s ridx:%d _phl_wr_offch_bcn_hdl failed\n",
					__func__, ridx);
				break;
			}
		}

		/* issue null-data on current channel */
		if ((mctx.role_map_ps) && (mctx.role_map_ps & BIT(ridx))) {
			wr = &phl_com->wifi_roles[ridx];
#ifdef RTW_WKARD_TXPAUSE_BF_ISSUE_NULL
			if (off_ch && rtw_phl_cmd_scan_inprogress(phl_info, hw_band))
				rtw_hal_scan_pause_tx_fifo(phl_info->hal, hw_band, true);
#endif
			psts = _phl_wr_offch_ps_hdl(phl_info, hw_band, wr, off_ch,
						      obj_priv, module_id,
						      issue_null_data);
			if (psts == RTW_PHL_STATUS_FAILURE) {
				PHL_ERR("%s ridx:%d _phl_wr_offch_ps_hdl failed\n",
					__func__, ridx);
				break;
			}
		}
	}

_exit:
#ifdef DBG_DBCC_MONITOR_TIME
	PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */

	return psts;
}

#else /*!CONFIG_MR_SUPPORT*/
static enum rtw_phl_status
_phl_wr_offch_hdl(struct phl_info_t *phl_info,
                  u8 hw_band,
                  struct rtw_wifi_role_t *wrole,
                  bool off_ch,
                  void *obj_priv,
                  u8 module_id,
                  bool (*issue_null_data)(void *priv, u8 ridx,
                                          u8 lidx, bool ps, u8 module_id))
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
	void *drv = phl_to_drvpriv(phl_info);
	struct rtw_chan_ctx *chanctx = NULL;
	u8 cur_ch = rtw_hal_get_cur_ch(phl_info->hal, hw_band);
	bool found = false;
	int ctx_num = 0;
#ifdef DBG_MONITOR_TIME
	u32 start_t = 0;

	PHL_FUN_MON_START(&start_t);
#endif /* DBG_MONITOR_TIME */

	ctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);

	if (ctx_num == 0){
		PHL_DBG("ctx_num == 0!\n");
		goto _exit;
	}

	_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
	phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {
		/* Find the chanctx same as the current channel */
		if(chanctx->chan_def.chan != cur_ch)
			continue;

		PHL_DBG("%s current chanctx found!\n", __FUNCTION__);
		found = true;
	}
	_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);

	if (!found) {
		PHL_DBG("No chanctx is the same as current channel!\n");
		goto _exit;
	}

	if (rtw_phl_role_is_client_category(wrole)
					&& wrole->mstate == MLME_LINKED) {
		if(issue_null_data == NULL){
			PHL_ERR("%s issue null_data function not found\n", __func__);
			_os_warn_on(1);
			goto _exit;
		}
#ifdef RTW_WKARD_TXPAUSE_BF_ISSUE_NULL
		if (off_ch && rtw_phl_cmd_scan_inprogress(phl_info, hw_band))
			rtw_hal_scan_pause_tx_fifo(phl_info->hal, hw_band, true);
#endif
		psts = _phl_wr_offch_ps_hdl(phl_info,
					      hw_band,
					      wrole,
					      off_ch,
					      obj_priv,
					      module_id,
					      issue_null_data);

	} else if (rtw_phl_role_is_ap_category(wrole)) {
		psts = _phl_wr_offch_bcn_hdl(phl_info,
					       hw_band,
					       wrole,
					       off_ch);
	}

_exit:
#ifdef DBG_MONITOR_TIME
	PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_MONITOR_TIME */

	return psts;
}
#endif

enum rtw_phl_status
phl_mr_offch_hdl(struct phl_info_t *phl_info,
                 struct rtw_wifi_role_t *wrole,
                 struct rtw_wifi_role_link_t *rlink,
                 bool off_ch,
                 void *obj_priv,
                 u8 module_id,
                 bool (*issue_null_data)(void *priv, u8 ridx, u8 lidx,
                                         bool ps, u8 module_id)
)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;

#ifdef CONFIG_MR_SUPPORT
	psts = _phl_mr_offch_hdl(phl_info, rlink->hw_band, off_ch, obj_priv,
	                          module_id, issue_null_data);
#else /*!CONFIG_MR_SUPPORT*/
	psts = _phl_wr_offch_hdl(phl_info, rlink->hw_band, wrole,
				  off_ch, obj_priv, module_id, issue_null_data);
#endif
	return psts;
}

#ifdef CONFIG_DBCC_SUPPORT
bool rtw_phl_mr_is_db(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);

	return (mr_ctl->is_db == true) ? true : false;
}

bool phl_mr_is_cckphy(struct phl_info_t *phl_info, u8 band_idx)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);

	return (mr_ctl->cck_phyidx == band_idx) ? true : false;
}

void rtw_phl_mr_cancel_dbcc_action(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);

#ifdef CONFIG_DBCC_FORCE
	if (is_frc_dbcc_mode(phl_info->phl_com)) {
		PHL_ERR("%s FORCE DBCC .....\n", __func__);
		return;
	}
#endif
	_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
	mr_ctl->trigger_dbcc_cfg = false;
	_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
}

bool phl_mr_is_trigger_dbcc(struct phl_info_t *phl_info)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);

	return mr_ctl->trigger_dbcc_cfg;
}

enum rtw_phl_status
phl_mr_trig_dbcc_enable(struct phl_info_t *phl_info, bool trig)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);

	/*hal_com->dbcc_en*/
	if (trig == true) {
		_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
		if (mr_ctl->is_db == false) /*single band*/
			mr_ctl->trigger_dbcc_cfg = true;
		_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
	} else {
		_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
		mr_ctl->trigger_dbcc_cfg = false;
		mr_ctl->is_db = true;
		_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
	}
	return RTW_PHL_STATUS_SUCCESS;
}

enum rtw_phl_status
rtw_phl_mr_trig_dbcc_enable(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	#ifdef CONFIG_DBCC_FORCE
	if (is_frc_dbcc_mode(phl_info->phl_com)) {
		PHL_INFO("%s FORCE DBCC .....\n", __func__);
		return RTW_PHL_STATUS_SUCCESS;
	}
	#endif
	return phl_mr_trig_dbcc_enable(phl_info, true);
}

static inline enum rtw_phl_status
phl_mr_dbcc_proto_hdl(struct phl_info_t *phl_info,
				enum phl_band_idx band_idx,
				struct rtw_wifi_role_t *wrole,
				bool dbcc_en)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct dbcc_proto_msg dbcc_proto = {0};
	u8 ret = _FAIL;
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
	dbcc_proto.dbcc_en = dbcc_en;
	dbcc_proto.wr = wrole;
	ret = mr_ctl->mr_ops.dbcc_protocol_hdl(phl_com->drv_priv, band_idx, &dbcc_proto);
#ifdef DBG_DBCC_MONITOR_TIME
	PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
	return (ret == _SUCCESS) ? RTW_PHL_STATUS_SUCCESS
				 : RTW_PHL_STATUS_FAILURE;
}

enum rtw_phl_status
rtw_phl_mr_dbcc_enable(void *phl,
				  enum phl_band_idx band_idx,
				  struct rtw_wifi_role_t *wrole)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct phl_msg msg = {0};
	struct phl_msg_attribute attr = {0};
	enum rtw_phl_status psts;

	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_MRC);
	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_DBCC_ENABLE);
	msg.band_idx = band_idx;
	msg.inbuf = (u8 *)wrole;

	psts = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);

	if (psts != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("%s: Dispr send msg fail!\n", __func__);
	}

	return psts;
}

static void _phl_mr_pause_trx(struct phl_info_t *phl_info, enum phl_band_idx band_idx)
{
	enum rtw_phl_status sts = RTW_PHL_STATUS_FAILURE;
	struct phl_data_ctl_t ctl = {0};
	struct phl_hci_trx_ops *hci_trx_ops = phl_info->hci_trx_ops;

#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
	ctl.id = PHL_MDL_MRC;

	ctl.cmd = PHL_DATA_CTL_SW_TX_PAUSE;
	sts = phl_data_ctrler(phl_info, &ctl, NULL);
	if (RTW_PHL_STATUS_SUCCESS != sts) {
		PHL_ERR("%s(): pause sw tx failure\n", __func__);
		goto err;
	}

	/* Stop DMA + Disable all of txch dma (Reset B1 TXBD idx to 0) */
	rtw_hal_dbcc_hci_ctrl(phl_info->hal, band_idx, true);
	/* - Redirect packets from old_band(B1) to new_band(B0)
	 *   [PCIE] Memory copy band1 TXBD to band0 DMA channel, update WD (DMA_CH/QSEL/...)
	 * - Or drop packets
	*/
	if (band_idx == HW_BAND_1)
		hci_trx_ops->tx_reset_hwband(phl_info, band_idx);

err:
#ifdef DBG_DBCC_MONITOR_TIME
	PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
	return;
}
static void _phl_mr_resume_trx(struct phl_info_t *phl_info, enum phl_band_idx band_idx)
{
	enum rtw_phl_status sts = RTW_PHL_STATUS_FAILURE;
	struct phl_data_ctl_t ctl = {0};
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */

	/* Enable all of txch dma */
	rtw_hal_dbcc_hci_ctrl(phl_info->hal, band_idx, false);

	ctl.id = PHL_MDL_MRC;

	ctl.cmd = PHL_DATA_CTL_SW_TX_RESUME;
	sts = phl_data_ctrler(phl_info, &ctl, NULL);
	if (RTW_PHL_STATUS_SUCCESS != sts) {
		PHL_ERR("%s(): resume sw tx failure\n", __func__);
		goto err;
	}

err:
#ifdef DBG_DBCC_MONITOR_TIME
	PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
	return;
}

enum phl_mdl_ret_code
_phl_mrc_module_dbcc_en_hdl(struct phl_info_t *phl_info,
					   struct rtw_wifi_role_t *role)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;

	struct rtw_wifi_role_link_t *rlink = NULL;
	bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;
	struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
	struct rtw_chan_def op_chdef = {0};
	u8 hal_ch = 0;
	int chctx_num;
#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: Rid(%d)\n",
		__FUNCTION__, role->id);
	rlink = &role->rlink[RTW_RLINK_PRIMARY];
	if (rlink->hw_band != HW_BAND_0) {
		PHL_ERR("wrole(%d) not in band0\n", role->id);
		_os_warn_on(1);
		ret = MDL_RET_FAIL;
		goto _exit;
	}

	hal_ch = rtw_hal_get_cur_ch(phl_info->hal, rlink->hw_band);

	/* 1.issue null(1) - pause Rx*/
	/*switch ch to op-chan*/
	chctx_num = phl_mr_get_chandef_by_band(phl_info, rlink->hw_band, &op_chdef);
	PHL_DUMP_CHAN_DEF_EX(&op_chdef);
	hal_ch = rtw_hal_get_cur_ch(phl_info->hal, rlink->hw_band);
	if (chctx_num == 1) {
		if (hal_ch != op_chdef.chan) {
			PHL_ERR("hw chan(%d) not in op-chan(%d)\n", hal_ch, op_chdef.chan);
			phl_set_ch_bw(phl_info, rlink->hw_band, &op_chdef, RFK_TYPE_DBCC_EN);
		}
	}

	if (ops->issue_null_data)
		core_issue_null_data = ops->issue_null_data;

	_phl_mr_offch_hdl(phl_info,
			  HW_BAND_0,
			  true,
			  phl_com->drv_priv,
			  PHL_MDL_MRC,
			  core_issue_null_data);

	/* 2.pause Tx- SW,HW*/
	_phl_mr_pause_trx(phl_info, HW_BAND_0);
	rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, true);

	/* 3.dbcc hw cfg (en)*/
	rtw_hal_dbcc_pre_cfg(phl_info->hal, phl_com, true);
	rtw_hal_dbcc_cfg(phl_info->hal, phl_com, true);

	/* 4.reallocate hw resouce - role*/
	phl_wifi_role_realloc_band(phl_info, role, rlink, HW_BAND_1);

	rtw_hal_dbcc_reset_hal(phl_info->hal);

	rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, false);
	rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_1, false);
	/* 5.unpause Tx- SW,HW*/
	_phl_mr_resume_trx(phl_info, HW_BAND_0);

	/* 6.issue null(0) - unpause Rx*/
	_phl_mr_offch_hdl(phl_info,
			  HW_BAND_0,
			  false,
			  phl_com->drv_priv,
			  PHL_MDL_MRC,
			  core_issue_null_data);

	phl_mr_trig_dbcc_enable(phl_info, false);
	ret = MDL_RET_SUCCESS;
	PHL_INFO("%s wr(%d) success....\n", __func__, role->id);
_exit:
#ifdef DBG_DBCC_MONITOR_TIME
	PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
	return ret;
}

enum phl_mdl_ret_code
_phl_mrc_module_dbcc_enable(void *dispr,
                            void *priv,
                            struct phl_msg *msg)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
	struct rtw_wifi_role_t *role = NULL;
	u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);

	if (module_id != PHL_MDL_MRC) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
			"%s: not mrc\n", __FUNCTION__);
		return MDL_RET_IGNORE;
	}

	role = (struct rtw_wifi_role_t *)msg->inbuf;
	return _phl_mrc_module_dbcc_en_hdl(phl_info, role);
}

enum rtw_phl_status
phl_mr_trig_dbcc_disable(struct phl_info_t *phl_info, bool trig)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);

	/*hal_com->dbcc_en*/
	if (trig == true) {
		_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
		if (mr_ctl->is_db == true) /*dual band*/
			mr_ctl->trigger_dbcc_cfg = true;
		_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
	} else {
		_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
		mr_ctl->trigger_dbcc_cfg = false;
		mr_ctl->is_db = false;
		_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
	}
	return RTW_PHL_STATUS_SUCCESS;
}

enum rtw_phl_status
rtw_phl_mr_trig_dbcc_disable(void *phl)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	#ifdef CONFIG_DBCC_FORCE
	if (is_frc_dbcc_mode(phl_info->phl_com)) {
		PHL_INFO("%s FORCE DBCC .....\n", __func__);
		return RTW_PHL_STATUS_SUCCESS;
	}
	#endif
	return phl_mr_trig_dbcc_disable(phl_info, true);
}

enum rtw_phl_status
rtw_phl_mr_dbcc_disable(void *phl,
				    enum phl_band_idx band_idx,
				    struct rtw_wifi_role_t *wrole)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct phl_msg msg = {0};
	struct phl_msg_attribute attr = {0};
	enum rtw_phl_status psts;

	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_MRC);
	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_DBCC_DISABLE);
	msg.band_idx = band_idx;
	msg.inbuf = (u8 *)wrole;

	psts = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);

	if (psts != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("%s: Dispr send msg fail!\n", __func__);
	}
	return psts;
}

static inline void
_phl_mr_band_info_cleanup(struct rtw_phl_com_t *phl_com, struct hw_band_ctl_t *band_ctrl)
{
	_os_mem_set(phl_com->drv_priv, &band_ctrl->cur_info, 0, sizeof(struct mr_info));
	band_ctrl->port_map = 0;
	band_ctrl->role_map = 0;
	band_ctrl->wmm_map = 0;
	band_ctrl->op_mode = MR_OP_NONE;
	band_ctrl->op_type = MR_OP_TYPE_NONE;
	band_ctrl->chctx_band_map = 0;

	if (band_ctrl->chan_ctx_queue.cnt) {
		PHL_ERR("%s Band_%d chan_ctx_queue.cnt(%d) not clearn up\n",
			__func__, band_ctrl->id, band_ctrl->chan_ctx_queue.cnt);
		_os_warn_on(1);
	}
}

static enum rtw_phl_status
_phl_dbcc_sync_rxfilter(struct phl_info_t *phl_info, enum phl_band_idx band_idx)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
	struct rtw_wifi_role_t *role = NULL, *wr = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 ridx = 0;
	enum rtw_phl_status ret = RTW_PHL_STATUS_SUCCESS;

	PHL_INFO("%s: band=%d\n", __func__, band_idx);
	wr = phl_mr_get_role_by_bandidx(phl_info, band_idx);
	if (wr == NULL) {
		PHL_INFO("%s: can't find any role for band(%d)\n", __func__, band_idx);
		_os_warn_on(1);
		ret = RTW_PHL_STATUS_FAILURE;
		goto exit;
	}

	rlink = &wr->rlink[0];

	ret = phl_mr_info_upt(phl_info, rlink);
	if (ret !=  RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("%s: phl_mr_info_upt fail(%d)\n", __func__, ret);
		goto exit;
	}

	ret = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
	if (ret !=  RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("%s: rtw_phl_mr_rx_filter_opt fail(%d)\n", __func__, ret);
		goto exit;
	}

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (band_ctrl->role_map & BIT(ridx)) {
			role = &(phl_com->wifi_roles[ridx]);
			rlink = &role->rlink[0];
			if (role->mstate == MLME_LINKED && rtw_phl_role_is_client_category(role)) {
				ret = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink, RX_FLTR_TYPE_MODE_STA_CONN);
				if (ret !=  RTW_PHL_STATUS_SUCCESS) {
					PHL_ERR("%s: rxfltr_type_by_mode fail(%d), role id=%d, rlink id=%d, mode=%d\n",
						__func__, ret, role->id, rlink->id, RX_FLTR_TYPE_MODE_STA_CONN);
					goto exit;
				}
			}
			if (rtw_phl_role_is_ap_category(role)) {
				ret = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink, RX_FLTR_TYPE_MODE_AP_CONN);
				if (ret !=  RTW_PHL_STATUS_SUCCESS) {
					PHL_ERR("%s: rxfltr_type_by_mode fail(%d), id=%d, rlink id=%d, mode=%d\n",
						__func__, ret, role->id, rlink->id, RX_FLTR_TYPE_MODE_AP_CONN);
					goto exit;
				}
			}
		}
	}
exit:
	return ret;
}

static enum phl_mdl_ret_code
_phl_mrc_module_dbcc_dis_pre_hdl(struct phl_info_t *phl_info,
						   struct rtw_wifi_role_t *role)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band0_ctrl = &(mr_ctl->band_ctrl[HW_BAND_0]);
	struct hw_band_ctl_t *band1_ctrl = &(mr_ctl->band_ctrl[HW_BAND_1]);
	struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
	struct rtw_chan_def op_chdef = {0};
	u8 role_num = 0, ridx;
	struct rtw_wifi_role_t *wr = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;
	int chctx_num = 0;
	enum phl_band_idx band_idx = HW_BAND_0;
	u8 hal_ch = 0;
	int b0_chctx_num = 0;
	int b1_chctx_num = 0;
	bool rd_enabled = false;
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */

	rlink = &role->rlink[RTW_RLINK_PRIMARY];

	if (ops->issue_null_data)
		core_issue_null_data = ops->issue_null_data;

	if (rlink->hw_band == HW_BAND_0)
		band_idx = HW_BAND_1;

	b0_chctx_num = phl_mr_get_chanctx_num(phl_info, band0_ctrl);
	PHL_INFO("%s Band_0 has chctx_num(%d)\n", __func__, b0_chctx_num);
	b1_chctx_num = phl_mr_get_chanctx_num(phl_info, band1_ctrl);
	PHL_INFO("%s Band_1 has chctx_num(%d)\n", __func__, b1_chctx_num);

	chctx_num = phl_mr_get_chandef_by_band(phl_info, band_idx, &op_chdef);
	PHL_INFO("Band_%d - op ch(%d), band(%d), offset(%d)\n",
			band_idx, op_chdef.chan, op_chdef.band, op_chdef.offset);

	if (chctx_num >= 1) {
		/*TODO - chctx_num == 2, get first chan_ctx*/
		hal_ch = rtw_hal_get_cur_ch(phl_info->hal, band_idx);
		if (hal_ch != op_chdef.chan) {
			PHL_ERR("hw chan(%d) not in op-chan(%d)\n", hal_ch, op_chdef.chan);
			phl_set_ch_bw(phl_info, band_idx, &op_chdef, RFK_TYPE_DBCC_DIS);

		}
	}

	/* 1.issue null(1) - pause Rx,stop beacon*/
	_phl_mr_offch_hdl(phl_info,
			  band_idx,
			  true,
			  phl_com->drv_priv,
			  PHL_MDL_MRC,
			  core_issue_null_data);

	/* 2.pause Tx- SW,HW*/
	_phl_mr_pause_trx(phl_info, HW_BAND_1);
	rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, true);
	rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_1, true);

	/* 3.reallocate hw resouce all of role in band 1,before disable cmac1*/
	role_num = phl_mr_get_role_num(phl_info, band1_ctrl);
	if (role_num == 0) {
		PHL_ERR("BAND_1 role num == 0\n");
		_os_warn_on(1);
	}
	PHL_INFO("%s band-1 - role_num:%d\n", __func__, role_num);
	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (band1_ctrl->role_map & BIT(ridx)) {
			wr = &(phl_com->wifi_roles[ridx]);
			psts = phl_wifi_role_realloc_band(phl_info, wr, &wr->rlink[RTW_RLINK_PRIMARY], HW_BAND_0);
			if (psts == RTW_PHL_STATUS_FAILURE) {
				PHL_ERR("%s phl_wifi_role_realloc_band failed\n",
					__func__);
				break;
			}
		}
	}

	/* 4.move bnad1's chan_ctx to band0*/
	if (b1_chctx_num) {
		if (b0_chctx_num != 0) {
			PHL_ERR("%s Band_0 has chctx_num(%d)\n", __func__, b0_chctx_num);
			_os_warn_on(1);
		}
		phl_chanctx_switch(phl_info, band0_ctrl, band1_ctrl);
		rtw_hal_dbcc_band_switch_hdl(phl_info->hal, HW_BAND_1);
	}

	/* 5.dbcc hw cfg (en = false)*/
	rtw_hal_dbcc_pre_cfg(phl_info->hal, phl_com, false);
	rtw_hal_dbcc_cfg(phl_info->hal, phl_com, false);

	/* 6. clean up all of sw vaule of band1*/
	_phl_mr_band_info_cleanup(phl_com, band1_ctrl);


	/* 7. restore_phy0_ch*/
#ifdef CONFIG_PHL_DFS
	rd_enabled = rtw_phl_is_radar_detect_enabled(phl_com, HW_BAND_0);
#endif
	rtw_hal_set_ch_bw(phl_info->hal, HW_BAND_0, &op_chdef, RFK_TYPE_FORCE_DO, rd_enabled, true);
	PHL_INFO("restore_phy0_ch - ch(%d), band(%d), offset(%d)\n",
			op_chdef.chan, op_chdef.band, op_chdef.offset);

	rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, false);
	rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_1, false);

	/* 8. unpause Tx- SW,HW*/
	_phl_mr_resume_trx(phl_info, HW_BAND_0);

	/* 9. check rx filter before unpause RX */
	_phl_dbcc_sync_rxfilter(phl_info, HW_BAND_0);

	/* 10. issue null(0) - unpause Rx*/
	_phl_mr_offch_hdl(phl_info,
			  HW_BAND_0,
			  false,
			  phl_com->drv_priv,
			  PHL_MDL_MRC,
			  core_issue_null_data);

	ret = MDL_RET_SUCCESS;

#ifdef DBG_DBCC_MONITOR_TIME
	PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */

	return ret;
}

static enum phl_mdl_ret_code
_phl_mrc_module_dbcc_dis_post_hdl(struct phl_info_t *phl_info,
						    struct rtw_wifi_role_t *role)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	phl_mr_trig_dbcc_disable(phl_info, false);
	rtw_hal_notification(phl_info->hal,
			     MSG_EVT_DBCC_DISABLE,
			     HW_BAND_0);

	ret = MDL_RET_SUCCESS;
	return ret;
}


enum phl_mdl_ret_code
_phl_mrc_module_dbcc_disable(void *dispr,
                             void *priv,
                             struct phl_msg *msg)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
	struct rtw_wifi_role_t *role = NULL;
	u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);

#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	phl_fun_monitor_start(&start_t, true, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	if ((module_id != PHL_MDL_MRC) &&
	    (module_id != PHL_FG_MDL_DISCONNECT) &&
	    (module_id != PHL_FG_MDL_CONNECT) &&
	    (module_id != PHL_FG_MDL_AP_STOP) &&
	    (module_id != PHL_FG_MDL_AP_START)) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
			"%s: msg not from DISC-CONT/AP-STOP/START FG or MRC\n", __FUNCTION__);
		ret = MDL_RET_IGNORE;
		goto _exit;
	}

	role = (struct rtw_wifi_role_t *)msg->inbuf;

	if ((MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_DISCONNECT_END) ||
	    (MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_AP_STOP_END)) {

		ret = _phl_mrc_module_dbcc_dis_pre_hdl(phl_info, role);
		PHL_INFO("%s wr(%d) phase-1 success....\n", __func__, role->id);
	}
	else if (MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_DBCC_DISABLE) {
		ret = _phl_mrc_module_dbcc_dis_post_hdl(phl_info, role);
		PHL_INFO("%s wr(%d) phase-2 success....\n", __func__, role->id);
	}

_exit:
#ifdef DBG_DBCC_MONITOR_TIME
	phl_fun_monitor_end(phl_info->phl_com, &start_t, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	return ret;
}

#ifdef CONFIG_DBCC_P2P_BG_LISTEN
static inline enum rtw_phl_status
phl_mr_dbcc_proto_hdl_ex(struct phl_info_t *phl_info,
				enum phl_band_idx band_idx,
				struct rtw_wifi_role_t *wrole,
				bool dbcc_en)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct dbcc_proto_msg dbcc_proto = {0};
	u8 ret = _FAIL;
#ifdef DBG_DBCC_MONITOR_TIME
	u32 start_t = 0;

	phl_fun_monitor_start(&start_t, true, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	dbcc_proto.dbcc_en = dbcc_en;
	dbcc_proto.wr = wrole;
	dbcc_proto.dbcc_cmd_direct = true;
	ret = mr_ctl->mr_ops.dbcc_protocol_hdl(phl_com->drv_priv, band_idx, &dbcc_proto);
#ifdef DBG_DBCC_MONITOR_TIME
	phl_fun_monitor_end(phl_info->phl_com, &start_t, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
	return (ret == _SUCCESS) ? RTW_PHL_STATUS_SUCCESS
				 : RTW_PHL_STATUS_FAILURE;
}
enum rtw_phl_status
_phl_mrc_module_dbcc_enable_ex(struct phl_info_t *phl_info,
						struct rtw_wifi_role_t *wrole)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	psts = phl_mr_dbcc_proto_hdl_ex(phl_info, wrole->rlink->hw_band, wrole, true);
	ret = _phl_mrc_module_dbcc_en_hdl(phl_info, wrole);

	PHL_DUMP_MR_EX(phl_info);
	return psts;
}

enum rtw_phl_status
phl_cmd_dbcc_en_hdl(struct phl_info_t *phl_info, u8 *param)
{
	struct rtw_wifi_role_t *wrole = (struct rtw_wifi_role_t *)param;

	return _phl_mrc_module_dbcc_enable_ex(phl_info, wrole);
}

enum rtw_phl_status
rtw_phl_cmd_dbcc_enable(struct rtw_wifi_role_t *wifi_role,
                      u8 band_idx,
                      enum phl_cmd_type cmd_type,
                      u32 cmd_timeout)
{
	struct phl_info_t *phl_info = wifi_role->phl_com->phl_priv;
	void *drv = wifi_role->phl_com->drv_priv;
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;

	if (cmd_type == PHL_CMD_DIRECTLY) {
		psts = _phl_mrc_module_dbcc_enable_ex(phl_info, wifi_role);
		goto _exit;
	}

	psts = phl_cmd_enqueue(phl_info,
	                       band_idx,
	                       MSG_EVT_DISCONNECT_CMD_DBCC_EN,
	                       (u8 *)wifi_role,
	                       0,
	                       NULL,
	                       cmd_type,
	                       cmd_timeout);

	if (is_cmd_failure(psts)) {
		/* Send cmd success, but wait cmd fail*/
		psts = RTW_PHL_STATUS_FAILURE;
	} else if (psts != RTW_PHL_STATUS_SUCCESS) {
		psts = RTW_PHL_STATUS_FAILURE;
	}
_exit:
	return psts;
}
enum rtw_phl_status
_phl_mrc_module_dbcc_disable_ex(struct phl_info_t *phl_info,
						struct rtw_wifi_role_t *wrole)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	ret = _phl_mrc_module_dbcc_dis_pre_hdl(phl_info, wrole);
	ret = _phl_mrc_module_dbcc_dis_post_hdl(phl_info, wrole);
	psts = phl_mr_dbcc_proto_hdl_ex(phl_info, wrole->rlink->hw_band, wrole, false);

	PHL_DUMP_MR_EX(phl_info);
	return psts;
}

enum rtw_phl_status
phl_cmd_dbcc_dis_hdl(struct phl_info_t *phl_info, u8 *param)
{
	struct rtw_wifi_role_t *wrole = (struct rtw_wifi_role_t *)param;

	return _phl_mrc_module_dbcc_disable_ex(phl_info, wrole);
}

enum rtw_phl_status
rtw_phl_cmd_dbcc_disable(struct rtw_wifi_role_t *wifi_role,
                      u8 band_idx,
                      enum phl_cmd_type cmd_type,
                      u32 cmd_timeout)
{
	struct phl_info_t *phl_info = wifi_role->phl_com->phl_priv;
	void *drv = wifi_role->phl_com->drv_priv;
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;

	if (cmd_type == PHL_CMD_DIRECTLY) {
		psts = _phl_mrc_module_dbcc_disable_ex(phl_info, wifi_role);
		goto _exit;
	}

	psts = phl_cmd_enqueue(phl_info,
	                       band_idx,
	                       MSG_EVT_CONNECT_CMD_DBCC_DIS,
	                       (u8 *)wifi_role,
	                       0,
	                       NULL,
	                       cmd_type,
	                       cmd_timeout);

	if (is_cmd_failure(psts)) {
		/* Send cmd success, but wait cmd fail*/
		psts = RTW_PHL_STATUS_FAILURE;
	} else if (psts != RTW_PHL_STATUS_SUCCESS) {
		psts = RTW_PHL_STATUS_FAILURE;
	}
_exit:
	return psts;
}
#endif /*CONFIG_DBCC_P2P_BG_LISTEN*/

#endif /*CONFIG_DBCC_SUPPORT*/

#ifdef CONFIG_CMD_DISP
static enum phl_mdl_ret_code
_phl_mrc_module_init(void *phl_info, void *dispr, void **priv)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	FUNCIN();
	*priv = phl_info;
	FUNCOUT();

	ret = MDL_RET_SUCCESS;
	return ret;
}

static void
_phl_mrc_module_deinit(void *dispr, void *priv)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	FUNCIN();
	FUNCOUT();

	ret = MDL_RET_SUCCESS;
}

static enum phl_mdl_ret_code
_phl_mrc_module_start(void *dispr, void *priv)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	FUNCIN();
#ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP
	/* Ensure M-BSSID map cleaned up in case of VAP roles were not turned
	   off normally. */
	do {
		struct mr_ctl_t *mr_ctl = phl_to_mr_ctrl(priv);
		u8 band_idx = 0;

		for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
			struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);

			band_ctrl->mbssid_map = 0;
			band_ctrl->mbssid_cnt = 0;
		}
	} while (0);
#endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */
	FUNCOUT();

	ret = MDL_RET_SUCCESS;
	return ret;
}

static enum phl_mdl_ret_code
_phl_mrc_module_stop(void *dispr, void *priv)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	FUNCIN();
	FUNCOUT();

	ret = MDL_RET_SUCCESS;
	return ret;
}

/* Same behaviour as rtw_phl_connect_prepare without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_connect_start_hdlr(struct phl_info_t *phl_info,
                                   struct rtw_wifi_role_t *wrole,
                                   struct rtw_wifi_role_link_t *rlink)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
		  __func__, wrole->id);
	if (rtw_phl_role_is_client_category(wrole)) {
		wrole->mstate = MLME_LINKING;
	}

	psts = phl_mr_info_upt(phl_info, rlink);
	if (psts != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("%s mr info upt failed\n", __func__);
		goto _exit;
	}

	if (!rtw_phl_role_is_ap_category(wrole)) {
		psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
			goto _exit;
		}
	}
	PHL_DUMP_MR_EX(phl_info);
_exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
		  __func__, psts);
	return psts;
}

/* Same behaviour as rtw_phl_connected without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_connect_end_hdlr(struct phl_info_t *phl_info,
				 struct rtw_wifi_role_t *wrole)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	u8 idx = 0;
	struct rtw_wifi_role_link_t *rlink = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
		  __func__, wrole->id);
	if (rtw_phl_role_is_client_category(wrole)) {
		psts = phl_role_notify(phl_info, wrole);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s sta role notify failed\n", __func__);
			goto _exit;
		}
	}

	if (!rtw_phl_role_is_ap_category(wrole)) {

		for (idx = 0; idx < wrole->rlink_num; idx++) {
			rlink = get_rlink(wrole, idx);
			if (rlink->mstate != MLME_LINKED)
				continue;

			psts = phl_mr_info_upt(phl_info, rlink);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s mr info upt failed\n", __func__);
				goto _exit;
			}

			psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
				goto _exit;
			}

			psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
								  RX_FLTR_TYPE_MODE_STA_CONN);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
				goto _exit;
			}

			psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_STA_CONN_END);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
				goto _exit;
			}
		}
	} else {
		for (idx = 0; idx < wrole->rlink_num; idx++) {
			rlink = get_rlink(wrole, idx);

			psts = phl_mr_info_upt(phl_info, rlink);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s mr info upt failed\n", __func__);
				goto _exit;
			}

			psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
								  RX_FLTR_TYPE_MODE_AP_CONN);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
				goto _exit;
			}
		}
	}

	PHL_DUMP_MR_EX(phl_info);
_exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
		  __func__, psts);
	return psts;
}

/* Same behaviour as rtw_phl_disconnect without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_disconnect_hdlr(struct phl_info_t *phl_info,
				struct rtw_wifi_role_t *wrole)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	u8 idx = 0;
	struct rtw_wifi_role_link_t *rlink = NULL;
#ifdef CONFIG_PHL_TDLS
	enum role_type rtype = PHL_RTYPE_STATION;
#endif
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
		  __func__, wrole->id);
#ifdef CONFIG_PHL_TDLS
	/* Disconnected with AP while there still exist linked TDLS peers */
	if (wrole->type == PHL_RTYPE_TDLS && wrole->mstate != MLME_LINKED) {
		psts = phl_wifi_role_change(phl_info, wrole, NULL, WR_CHG_TYPE, (u8*)&rtype);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			RTW_ERR("%s - change to phl role type = %d fail with error = %d\n", __func__, rtype, psts);
			goto _exit;
		}
	}
#endif
	if (rtw_phl_role_is_client_category(wrole)) {
		psts = phl_role_notify(phl_info, wrole);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s sta role notify failed\n", __func__);
			goto _exit;
		}
	}

	if (!rtw_phl_role_is_ap_category(wrole)) {

		for (idx = 0; idx < wrole->rlink_num; idx++) {
			rlink = get_rlink(wrole, idx);

			psts = phl_mr_info_upt(phl_info, rlink);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s mr info upt failed\n", __func__);
				goto _exit;
			}

			psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
				goto _exit;
			}

			psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
								  RX_FLTR_TYPE_MODE_STA_DIS_CONN);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
				goto _exit;
			}

			psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_STA_DIS_CONN);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
				goto _exit;
			}

			rtw_hal_disconnect_notify(phl_info->hal, &rlink->chandef);
		}
	} else {
		for (idx = 0; idx < wrole->rlink_num; idx++) {
			rlink = get_rlink(wrole, idx);

			psts = phl_mr_info_upt(phl_info, rlink);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s mr info upt failed\n", __func__);
				goto _exit;
			}

			psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
								  RX_FLTR_TYPE_MODE_AP_DIS_CONN);
			if (psts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
				goto _exit;
			}
		}
	}

	PHL_DUMP_MR_EX(phl_info);
_exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
		  __func__, psts);
	return psts;
}

/* Same behaviour as rtw_phl_ap_started without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_ap_started_hdlr(struct phl_info_t *phl_info,
				struct rtw_wifi_role_t *wrole)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
		  __func__, wrole->id);
	psts = phl_role_notify(phl_info, wrole);
	if (psts != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("%s role notify failed\n", __func__);
		goto _exit;
	}

	for (idx = 0; idx < wrole->rlink_num; idx++) {
		rlink = get_rlink(wrole, idx);

		psts = phl_mr_info_upt(phl_info, rlink);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s mr info upt failed\n", __func__);
			goto _exit;
		}
		psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
			goto _exit;
		}

		psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_AP_START);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
			goto _exit;
		}
	}

	PHL_DUMP_MR_EX(phl_info);
_exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
		  __func__, psts);
	return psts;
}


/* Same behaviour as rtw_phl_ap_stop without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_ap_stop_hdlr(struct phl_info_t *phl_info,
				struct rtw_wifi_role_t *wrole)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	u8 idx = 0;
	struct rtw_wifi_role_link_t *rlink = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
		  __func__, wrole->id);
	wrole->mstate = MLME_NO_LINK;
	psts = phl_role_notify(phl_info, wrole);
	if (psts != RTW_PHL_STATUS_SUCCESS) {
		PHL_ERR("%s role notify failed\n", __func__);
		goto _exit;
	}

	for (idx = 0; idx < wrole->rlink_num; idx++) {
		rlink = get_rlink(wrole, idx);
		rtw_hal_disconnect_drop_all_pkt(phl_info->hal,
				rtw_phl_get_stainfo_self(phl_info, rlink));
		psts = phl_mr_info_upt(phl_info, rlink);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s mr info upt failed\n", __func__);
			goto _exit;
		}
		psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
			goto _exit;
		}

		psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_AP_STOP);
		if (psts != RTW_PHL_STATUS_SUCCESS) {
			PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
			goto _exit;
		}

		rtw_hal_disconnect_notify(phl_info->hal, &rlink->chandef);
	}

	PHL_DUMP_MR_EX(phl_info);
_exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
		  __func__, psts);
	return psts;
}

enum phl_mdl_ret_code
_phl_mrc_module_swch_start_hdlr(void *dispr,
				void *priv,
				struct phl_msg *msg)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
	struct phl_module_op_info op_info = {0};
	struct rtw_wifi_role_t *role = NULL;
	struct rtw_chan_def chandef = {0};
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);
	struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
	u8 idx = 0xff, hw_band = 0;
	struct rtw_wifi_role_link_t *rlink = NULL;
	bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;

	phl_dispr_get_idx(dispr, &idx);
	/*
	* Handle mr offchan before switching channel when
	* STA connect & AP start.
	*/
	if((module_id != PHL_FG_MDL_CONNECT) &&
	   (module_id != PHL_FG_MDL_AP_START) &&
	   (module_id != PHL_FG_MDL_SCAN)){
		PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
		"%s: not connect/apstart/scan\n", __FUNCTION__);
		ret = MDL_RET_IGNORE;
		goto _exit;
	}
	PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
		"%s[%d]: MSG_EVT_SWCH_START\n", __FUNCTION__, msg->band_idx);

	op_info.op_code = FG_REQ_OP_GET_ROLE;
	if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
		!= RTW_PHL_STATUS_SUCCESS){
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
				"Query wifi role fail!\n");
		goto _exit;
	}
	role = (struct rtw_wifi_role_t *)op_info.outbuf;
	if(role == NULL){
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
			"%s: role is NULL\n", __FUNCTION__);
		goto _exit;
	}

	op_info.op_code = FG_REQ_OP_GET_ROLE_LINK;
	if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
		!= RTW_PHL_STATUS_SUCCESS){
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
				"Query wifi role link fail!\n");
		goto _exit;
	}
	rlink = (struct rtw_wifi_role_link_t *)op_info.outbuf;
	if(rlink == NULL){
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
			"%s: role link is NULL\n", __FUNCTION__);
		goto _exit;
	}

	hw_band = rlink->hw_band;

	/*
	* If we are already on STA/AP channel,
	* offch is unnecessary.
	*/
	if((module_id == PHL_FG_MDL_CONNECT) ||
	   (module_id == PHL_FG_MDL_AP_START)){
	   	#ifdef CONFIG_MR_SUPPORT
		chandef = mr_ctl->hal_com->band[hw_band].cur_chandef;

		if(rlink->chandef.chan == chandef.chan){
			ret = MDL_RET_SUCCESS;
			goto _exit;
		}
		#else
		ret = MDL_RET_SUCCESS;
		goto _exit;
		#endif
	}

	if (ops->issue_null_data)
		core_issue_null_data = ops->issue_null_data;

	phl_mr_offch_hdl(phl_info,
	                 role,
	                 rlink,
	                 true,
	                 phl_com->drv_priv,
	                 module_id,
	                 core_issue_null_data);

	ret = MDL_RET_SUCCESS;
_exit:
	return ret;
}

enum phl_mdl_ret_code
_phl_mrc_module_swch_done_hdlr(void *dispr,
			       void *priv,
			       struct phl_msg *msg)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct rtw_wifi_role_t *role = NULL;
	u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);
	struct phl_scan_channel scan_ch = {0};
	struct rtw_phl_evt_ops *ops = &phl_info->phl_com->evt_ops;
	struct rtw_wifi_role_link_t *rlink = NULL;
	bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;

	/*
	* Handle mr offchan after switching channel to op channel
	*/
	if(module_id != PHL_FG_MDL_SCAN){
		ret = MDL_RET_IGNORE;
		goto _exit;
	}
	PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
		"%s[%d]: MSG_EVT_SWCH_DONE\n", __FUNCTION__, msg->band_idx);
	scan_ch = *(struct phl_scan_channel *)(msg->inbuf);

	/* Issue null 0 and resume beacon when BACKOP during scanning */
	if(scan_ch.scan_mode != BACKOP_MODE){
		ret = MDL_RET_SUCCESS;
		goto _exit;
	}

	role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
	rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[1].ptr;

	if (ops->issue_null_data)
		core_issue_null_data = ops->issue_null_data;

	phl_mr_offch_hdl(phl_info,
	                 role,
	                 rlink,
	                 false,
	                 phl_com->drv_priv,
	                 module_id,
	                 core_issue_null_data);

	ret = MDL_RET_SUCCESS;
_exit:
	return ret;
}


static enum rtw_phl_status
_mrc_module_chg_op_chdef_end_pre_hdlr(u8 *param)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct chg_opch_param *ch_param = (struct chg_opch_param *)param;
	struct rtw_wifi_role_t *wrole = ch_param->wrole;
	struct phl_info_t *phl = wrole->phl_com->phl_priv;
	struct rtw_phl_evt_ops *ops = &phl->phl_com->evt_ops;
	bool (*core_issue_null)(void *, u8, u8, bool, u8) = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
		  __func__, wrole->id);
	/* Handle mr offchan after switching channel to new op channel */
	/* If the new pri-ch is as same as ori pri-ch, offch is unnecessary. */
	if(ch_param->new_chdef.chan == ch_param->ori_chdef.chan) {
		psts = RTW_PHL_STATUS_SUCCESS;
		goto exit;
	}

	if (ops->issue_null_data) {
		core_issue_null = ops->issue_null_data;
	} else {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Ops issue_null_data is NULL\n",
			__func__);
	}

	if (RTW_PHL_STATUS_SUCCESS != phl_mr_offch_hdl(phl,
	                                               wrole,
	                                               ch_param->rlink,
	                                               false,
	                                               phl->phl_com->drv_priv,
	                                               PHL_MDL_MRC,
	                                               core_issue_null)) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "%s: Fail to offch\n",
			__func__);
		goto exit;
	}
	psts = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
		  __func__, psts);
	return psts;
}

static enum phl_mdl_ret_code
_mrc_module_chg_op_chdef_start_hdlr(void *dispr, void *priv,
			 struct phl_msg *msg)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	struct phl_info_t *phl = (struct phl_info_t *)priv;
	struct rtw_phl_evt_ops *ops = &phl->phl_com->evt_ops;
	struct chg_opch_param *ch_param = NULL;
	struct rtw_wifi_role_t *wrole = NULL;
	bool (*core_issue_null)(void *, u8, u8, bool, u8) = NULL;
	u8 *cmd = NULL;
	u32 cmd_len;

	if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_GENERAL) {
		ret = MDL_RET_IGNORE;
		goto exit;
	}
	if (phl_cmd_get_cur_cmdinfo(phl, msg->band_idx, msg, &cmd, &cmd_len)
						!= RTW_PHL_STATUS_SUCCESS) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Fail to get cmd info \n",
			  __func__);
		goto exit;
	}
	ch_param = (struct chg_opch_param *)cmd;
	wrole = ch_param->wrole;
	PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: wrole->id(%d)\n",
		  __func__, wrole->id);
	/* Handle mr offchan before switching channel */
	/* If the new pri-ch is as same as old pri-ch, offch is unnecessary. */
	if (ch_param->new_chdef.chan == ch_param->ori_chdef.chan) {
		ret = MDL_RET_SUCCESS;
		goto exit;
	}
	if (ops->issue_null_data) {
		core_issue_null = ops->issue_null_data;
	} else {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Ops issue_null_data is NULL\n",
			__func__);
	}

	if (RTW_PHL_STATUS_SUCCESS != phl_mr_offch_hdl(phl,
	                                               wrole,
	                                               ch_param->rlink,
	                                               true,
	                                               phl->phl_com->drv_priv,
	                                               MSG_MDL_ID_FIELD(msg->msg_id),
	                                               core_issue_null)) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "%s: Fail to offch\n",
			__func__);
		goto exit;
	}
	ret = MDL_RET_SUCCESS;
exit:
	return ret;
}

static enum phl_mdl_ret_code
_mrc_module_msg_pre_hdlr(void *dispr, void *priv, struct phl_msg *msg)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	struct phl_info_t *phl = (struct phl_info_t *)priv;
	u8 *cmd = NULL;
	u32 cmd_len;

	switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
	case MSG_EVT_CHG_OP_CH_DEF_END:
		if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_GENERAL) {
			ret = MDL_RET_IGNORE;
			break;
		}
		PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: MSG_EVT_CHG_OP_CH_DEF_END\n",
			__FUNCTION__);
		if (RTW_PHL_STATUS_SUCCESS != phl_cmd_get_cur_cmdinfo(phl,
					msg->band_idx, msg, &cmd, &cmd_len)) {
			PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Fail to get cmd info \n",
				  __func__);
			break;
		}
		if (RTW_PHL_STATUS_SUCCESS !=
			_mrc_module_chg_op_chdef_end_pre_hdlr(cmd)) {
			break;
		}
		ret = MDL_RET_SUCCESS;
		break;
	default:
		PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s: MDL ID(%d), Event ID(%d), Not handle event in pre-phase\n",
			__FUNCTION__, MSG_MDL_ID_FIELD(msg->msg_id),
			MSG_EVT_ID_FIELD(msg->msg_id));
		ret = MDL_RET_IGNORE;
		break;
	}
	if (ret == MDL_RET_FAIL) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_,
			"%s: MDL(%d), EVT(%d), handle event failed\n",
			__FUNCTION__, MSG_MDL_ID_FIELD(msg->msg_id),
			MSG_EVT_ID_FIELD(msg->msg_id));
	}
	return ret;
}

static enum phl_mdl_ret_code
_mrc_module_msg_post_hdl(void *dispr,
			 void *priv,
			 struct phl_msg *msg)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;
	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
	struct rtw_wifi_role_t *role = NULL;
	struct rtw_chan_def chandef = {0};
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
#if defined(CONFIG_STA_CMD_DISPR) || defined(CONFIG_AP_CMD_DISPR)
	struct phl_module_op_info op_info = {0};
#endif
	struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
	u8 idx = 0xff, hw_band = 0;
	struct rtw_phl_stainfo_t *sta = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;

	u8 *cmd = NULL;
	u32 cmd_len;

	if (ops->issue_null_data)
		core_issue_null_data = ops->issue_null_data;

	phl_dispr_get_idx(dispr, &idx);
	switch(MSG_EVT_ID_FIELD(msg->msg_id)) {
		case MSG_EVT_CHG_OP_CH_DEF_START:
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s: MSG_EVT_CHG_OP_CH_DEF_START\n", __FUNCTION__);
			ret = _mrc_module_chg_op_chdef_start_hdlr(dispr, priv, msg);
		break;

		case MSG_EVT_SCAN_START:
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_SCAN_END:
			if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_SCAN){
				ret = MDL_RET_IGNORE;
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_SCAN_END\n", __FUNCTION__, idx);

			role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			/* use primary link to serve scan request for legacy/MLD */
			rlink = &role->rlink[RTW_RLINK_PRIMARY];
			hw_band = rlink->hw_band;

			if (phl_mr_get_chandef(phl_info,
						role,
						rlink,
						false,
						&chandef) !=
					RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s phl_mr_get_chandef failed\n", __func__);
				break;
			}

			PHL_DUMP_CHAN_DEF_EX(&chandef);

			phl_set_ch_bw(phl_info, hw_band, &chandef, RFK_TYPE_SCAN_BK_OP);
			phl_mr_offch_hdl(phl_info,
					  role,
					  rlink,
					  false,
					  phl_com->drv_priv,
					  MSG_MDL_ID_FIELD(msg->msg_id),
					  core_issue_null_data);
			ret = MDL_RET_SUCCESS;
			break;

		case MSG_EVT_SWCH_START:
			if (MSG_MDL_ID_FIELD(msg->msg_id) == PHL_MDL_GENERAL) {
				struct setch_param *ch_param = NULL;

				if (phl_cmd_get_cur_cmdinfo(phl_info, idx, msg, &cmd, &cmd_len) ==
					RTW_PHL_STATUS_SUCCESS) {
					ch_param = (struct setch_param *)cmd;
					PHL_INFO("[MRC] GEN_CMD_MDL Switch chan ......\n");
					PHL_INFO("[MRC] wrole idx:%d\n", ch_param->wrole->id);
					PHL_INFO("[MRC] ch:%d, bw:%d, offset:%d\n",
							ch_param->chdef.chan,
							ch_param->chdef.bw,
							ch_param->chdef.offset);
					PHL_INFO("[MRC] rt_type:%d\n", ch_param->rt_type);
					PHL_INFO("[MRC] GEN_CMD_MDL Switch chan ......\n");
				}
				ret = MDL_RET_SUCCESS;
			} else {
				ret = _phl_mrc_module_swch_start_hdlr(dispr,
								      priv,
								      msg);
			}
			break;
		case MSG_EVT_SWCH_DONE:
			ret = _phl_mrc_module_swch_done_hdlr(dispr,
							     priv,
							     msg);
			break;

		case MSG_EVT_TSF_SYNC_DONE:
			if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_GENERAL){
				ret = MDL_RET_IGNORE;
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_TSF_SYNC_DONE\n", __FUNCTION__, idx);

			if (phl_cmd_get_cur_cmdinfo(phl_info, msg->band_idx,
						    msg, &cmd, &cmd_len)
						!= RTW_PHL_STATUS_SUCCESS) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Fail to get cmd info \n",
					__func__);
				break;
			}
			sta = (struct rtw_phl_stainfo_t *)cmd;
			if(sta == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: sta is NULL\n", __FUNCTION__);
				break;
			}
			SET_STATUS_FLAG(sta->rlink->status, RLINK_STATUS_TSF_SYNC);
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_TDLS_SYNC:
			if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_MRC){
				ret = MDL_RET_IGNORE;
				break;
			}

			/*
			 * MR decides to call mcc enable or not
			 */
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_TDLS_SYNC\n", __FUNCTION__, idx);

			role = (struct rtw_wifi_role_t *)msg->inbuf;
			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[0].ptr;
			if(rlink == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: rlink is NULL\n", __FUNCTION__);
				break;
			}

			if (phl_mr_info_upt(phl_info, rlink) != RTW_PHL_STATUS_SUCCESS) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "phl_mr_info_upt failed\n");
				break;
			}
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_TX_RESUME:
			if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_MRC){
				ret = MDL_RET_IGNORE;
				break;
			}

			/*
			 * MR resume the tx of the role in remain chanctx
			 */
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_TX_RESUME\n", __FUNCTION__, idx);
			role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[1].ptr;
			if(rlink == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role link is NULL\n", __FUNCTION__);
				break;
			}

			phl_mr_offch_hdl(phl_info,
			                 role,
			                 rlink,
			                 false,
			                 phl_com->drv_priv,
			                 MSG_MDL_ID_FIELD(msg->msg_id),
			                 core_issue_null_data);

			ret = MDL_RET_SUCCESS;
			break;

		case MSG_EVT_CONNECT_START:
#ifdef CONFIG_STA_CMD_DISPR
			if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
			     MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_ADD_DEL_STA) {
				ret = MDL_RET_IGNORE;
				break;
			}

			role = (struct rtw_wifi_role_t *)msg->inbuf;
			if(role == NULL) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				"%s[%d]: MSG_EVT_CONNECT_START\n",
				__FUNCTION__, idx);
			rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[0].ptr;
			if(rlink == NULL) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role link is NULL\n", __FUNCTION__);
				break;
			}
			hw_band = rlink->hw_band;

			#ifdef CONFIG_DBCC_SUPPORT
			if (phl_mr_is_trigger_dbcc(phl_info)) {
				if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, true) !=
							   RTW_PHL_STATUS_SUCCESS) {
					PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
					ret =  MDL_RET_FAIL;
				} else {
					ret =  MDL_RET_PENDING;
				}
			} else
			#endif /*CONFIG_DBCC_SUPPORT*/
			{
				if(_phl_mrc_module_connect_start_hdlr(phl_info, role, rlink) !=
					RTW_PHL_STATUS_SUCCESS) {
					break;
				}

				rtw_hal_notification(phl_info->hal, MSG_EVT_ID_FIELD(msg->msg_id),
						     hw_band);
				ret = MDL_RET_SUCCESS;
			}
#endif
			break;
#ifdef CONFIG_DBCC_SUPPORT
		case MSG_EVT_DBCC_ENABLE:
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				"%s: MSG_EVT_DBCC_ENABLE\n",
				__FUNCTION__);
			ret = _phl_mrc_module_dbcc_enable(dispr, priv, msg);
			if (ret != MDL_RET_SUCCESS) {
				PHL_ERR("MSG_EVT_DBCC_ENABLE failed\n");
				_os_warn_on(1);
			}
			phl_disp_eng_clr_pending_msg(phl_info, msg->band_idx);
			break;

#ifdef CONFIG_DBCC_P2P_BG_LISTEN
		case MSG_EVT_CONNECT_END_DBCC_EN:
		case MSG_EVT_DISCONNECT_END_DBCC_EN:
			role = (struct rtw_wifi_role_t *)msg->inbuf;
			if(role == NULL) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				"%s[%d]: MSG_EVT_CONNECT_END_DBCC_EN\n",
				__FUNCTION__, idx);

			if (phl_mr_is_trigger_dbcc(phl_info)) {
				if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, true) !=
							   RTW_PHL_STATUS_SUCCESS) {
					PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
					ret =  MDL_RET_FAIL;
				} else {
					ret =  MDL_RET_PENDING;
				}
			} else {
				ret = MDL_RET_SUCCESS;
			}
			break;
#endif /*CONFIG_DBCC_P2P_BG_LISTEN*/
#endif
		case MSG_EVT_CONNECT_END:
#ifdef CONFIG_STA_CMD_DISPR
			if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
			    MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_ADD_DEL_STA) {
				ret = MDL_RET_IGNORE;
				break;
			}

			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_CONNECT_END\n", __FUNCTION__, idx);

			op_info.op_code = FG_REQ_OP_GET_ROLE;
			if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
				!= RTW_PHL_STATUS_SUCCESS){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "Query wifi role fail!\n");
				break;
			}
			role = (struct rtw_wifi_role_t *)op_info.outbuf;
			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			op_info.op_code = FG_REQ_OP_GET_ROLE_LINK;
			if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
				!= RTW_PHL_STATUS_SUCCESS){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
						"Query wifi role link fail!\n");
				break;
			}
			rlink = (struct rtw_wifi_role_link_t *)op_info.outbuf;
			if(rlink == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					"%s: role link is NULL\n", __FUNCTION__);
				break;
			}

			hw_band = rlink->hw_band;

			if(_phl_mrc_module_connect_end_hdlr(phl_info, role) !=
				RTW_PHL_STATUS_SUCCESS) {
				break;
			}

			rtw_hal_notification(phl_info->hal, MSG_EVT_ID_FIELD(msg->msg_id),
					     hw_band);
#endif
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_DISCONNECT_PREPARE:
#ifdef CONFIG_STA_CMD_DISPR
			if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
			    MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_DISCONNECT
			) {
				ret = MDL_RET_IGNORE;
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_DISCONNECT_PREPARE\n", __FUNCTION__, idx);
			role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;

			if (role == NULL) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}
#ifdef CONFIG_TWT
			rtw_phl_twt_free_all_twt_by_role(phl_info,
							    role);
#endif
#endif
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_DISCONNECT:
#ifdef CONFIG_STA_CMD_DISPR
			if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
			    MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_DISCONNECT &&
			    MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_ADD_DEL_STA) {
				ret = MDL_RET_IGNORE;
				break;
			}

			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_DISCONNECT\n", __FUNCTION__, idx);

			role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;

			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			if(_phl_mrc_module_disconnect_hdlr(phl_info, role) !=
				RTW_PHL_STATUS_SUCCESS) {
				break;
			}
#endif
			ret = MDL_RET_SUCCESS;
			break;

		case MSG_EVT_DISCONNECT_END:
		case MSG_EVT_AP_STOP_END:
#if defined(CONFIG_STA_CMD_DISPR) || defined(CONFIG_AP_CMD_DISPR)
			if ((MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_DISCONNECT) &&
			     (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT) &&
			     (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_STOP) &&
			     (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START)) {
				ret = MDL_RET_IGNORE;
				break;
			}

			if (MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_DISCONNECT_END) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_DISCONNECT_END\n", __FUNCTION__, idx);
			} else {
				PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_AP_STOP_END\n", __FUNCTION__, idx);
#ifdef CONFIG_DIG_TDMA
				rtw_hal_notification(phl_info->hal, MSG_EVT_AP_STOP_END, HW_BAND_0);
#endif
			}
			#ifdef CONFIG_DBCC_SUPPORT
			if (phl_mr_is_trigger_dbcc(phl_info)) {
				ret = _phl_mrc_module_dbcc_disable(dispr, priv, msg);

				if (ret != MDL_RET_SUCCESS)
					break;

				/* core trx-nss protocol handshake*/
				role = (struct rtw_wifi_role_t *)msg->inbuf;
				if(role == NULL){
					PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
						  "%s: role is NULL\n", __FUNCTION__);
					break;
				}

				if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, false) !=
					RTW_PHL_STATUS_SUCCESS) {
					PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
					ret = MDL_RET_FAIL;
					break;
				}
				ret = MDL_RET_PENDING;
			}else
			#endif /*CONFIG_DBCC_SUPPORT*/
			{
				ret = MDL_RET_SUCCESS;
			}
#endif
			break;

#ifdef CONFIG_DBCC_SUPPORT
		case MSG_EVT_DBCC_DISABLE:
			ret = _phl_mrc_module_dbcc_disable(dispr, priv, msg);
			if (ret != MDL_RET_SUCCESS) {
				PHL_ERR("MSG_EVT_DBCC_DISABLE failed\n");
				_os_warn_on(1);
			}
			phl_disp_eng_clr_pending_msg(phl_info, msg->band_idx);
			break;
#endif

		case MSG_EVT_AP_START_PREPARE:
#ifdef CONFIG_AP_CMD_DISPR
			if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START) {
				ret = MDL_RET_IGNORE;
				break;
			}

			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_AP_START_PREPARE\n", __FUNCTION__, idx);

			op_info.op_code = FG_REQ_OP_GET_ROLE;

			if (phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
				!= RTW_PHL_STATUS_SUCCESS) {
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "Query wifi role fail!\n");
				break;
			}
			role = (struct rtw_wifi_role_t *)op_info.outbuf;
			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			op_info.op_code = FG_REQ_OP_GET_ROLE_LINK;
			if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
				!= RTW_PHL_STATUS_SUCCESS){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
						"Query wifi role link fail!\n");
				break;
			}

			rlink = (struct rtw_wifi_role_link_t *)op_info.outbuf;
			if(rlink == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					"%s: role link is NULL\n", __FUNCTION__);
				break;
			}

			#ifdef CONFIG_DBCC_SUPPORT
			if (phl_mr_is_trigger_dbcc(phl_info)) {
				if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, true) !=
							  RTW_PHL_STATUS_SUCCESS) {
					PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
					ret = MDL_RET_FAIL;
				} else {
					ret = MDL_RET_PENDING;
				}
			} else
			#endif /*CONFIG_DBCC_SUPPORT*/
			{
				ret = MDL_RET_SUCCESS;
			}
#endif
			break;
		case MSG_EVT_AP_START:
#ifdef CONFIG_AP_CMD_DISPR
			if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START){
				ret = MDL_RET_IGNORE;
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_AP_START\n", __FUNCTION__, idx);

			op_info.op_code = FG_REQ_OP_GET_ROLE;
			if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
				!= RTW_PHL_STATUS_SUCCESS){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "Query wifi role fail!\n");
				break;
			}

			role = (struct rtw_wifi_role_t *)op_info.outbuf;
			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			if(_phl_mrc_module_ap_started_hdlr(phl_info, role) !=
				RTW_PHL_STATUS_SUCCESS) {
				break;
			}
#endif
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_AP_START_END:
#ifdef CONFIG_AP_CMD_DISPR
			if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START){
				ret = MDL_RET_IGNORE;
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_AP_START_END\n", __FUNCTION__, idx);

			role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			if(msg->inbuf == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s:AP start status info not found!\n",
					  __FUNCTION__);
				ret = MDL_RET_FAIL;
				break;
			}
			if(*(msg->inbuf) != RTW_PHL_STATUS_SUCCESS){
				if(_phl_mrc_module_ap_stop_hdlr(phl_info, role)
				   != RTW_PHL_STATUS_SUCCESS) {
					break;
				}
			} else {
#ifdef CONFIG_DIG_TDMA
				rtw_hal_notification(phl_info->hal, MSG_EVT_AP_START_END, HW_BAND_0);
#endif
			}
#endif
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_AP_STOP:
#ifdef CONFIG_AP_CMD_DISPR
			if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_STOP){
				ret = MDL_RET_IGNORE;
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_AP_STOP\n", __FUNCTION__, idx);

			role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;

			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			if(_phl_mrc_module_ap_stop_hdlr(phl_info, role) !=
				RTW_PHL_STATUS_SUCCESS) {
				break;
			}
#endif
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_ECSA_SWITCH_DONE:
#ifdef CONFIG_PHL_ECSA
			if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_ECSA){
				ret = MDL_RET_IGNORE;
				break;
			}
			PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
				  "%s[%d]: MSG_EVT_ECSA_SWITCH_DONE\n", __FUNCTION__, idx);
			role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;

			if(role == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role is NULL\n", __FUNCTION__);
				break;
			}

			rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[1].ptr;
			if(rlink == NULL){
				PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
					  "%s: role link is NULL\n", __FUNCTION__);
				break;
			}
			hw_band = rlink->hw_band;
			phl_mr_stop_all_beacon(phl_info, role, hw_band, false);
#endif /* CONFIG_PHL_ECSA */
			ret = MDL_RET_SUCCESS;
			break;
		case MSG_EVT_SER_M5_READY:
			if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_SER) {
				ret = MDL_RET_IGNORE;
				break;
			}

			PHL_INFO("%s: MSG_EVT_SER_M5_READY\n", __func__);
			phl_mr_err_recovery(phl_info, MSG_EVT_ID_FIELD(msg->msg_id));
			ret = MDL_RET_SUCCESS;
			break;
		default:
			ret = MDL_RET_SUCCESS;
			break;
	}
	if (ret == MDL_RET_FAIL) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_,
			"%s: MDL(%d), EVT(%d), handle event failed\n",
			__FUNCTION__, MSG_MDL_ID_FIELD(msg->msg_id),
			MSG_EVT_ID_FIELD(msg->msg_id));
	}

	return ret;
}

static enum phl_mdl_ret_code
_phl_mrc_module_msg_hdlr(void *dispr, void *priv, struct phl_msg *msg)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	FUNCIN();
	if (IS_MSG_FAIL(msg->msg_id)) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
			  "%s: cmd dispatcher notify cmd failure: 0x%x.\n",
			   __FUNCTION__, msg->msg_id);
		FUNCOUT();
		return MDL_RET_FAIL;
	}
	if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
		ret = _mrc_module_msg_pre_hdlr(dispr, priv, msg);
	} else {
		ret = _mrc_module_msg_post_hdl(dispr, priv, msg);
	}
	FUNCOUT();
	return ret;
}

static enum phl_mdl_ret_code
_phl_mrc_module_set_info(void *dispr,
			 void *priv,
			 struct phl_module_op_info *info)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	FUNCIN();
	FUNCOUT();

	ret = MDL_RET_SUCCESS;
	return ret;
}

static enum phl_mdl_ret_code
_phl_mrc_module_query_info(void *dispr,
			   void *priv,
			   struct phl_module_op_info *info)
{
	enum phl_mdl_ret_code ret = MDL_RET_FAIL;

	FUNCIN();
	FUNCOUT();

	ret = MDL_RET_SUCCESS;
	return ret;
}

static enum rtw_phl_status
_phl_role_bk_module_init(struct phl_info_t *phl_info)
{
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	struct phl_bk_module_ops *bk_ops = &mr_ctl->bk_ops;

	bk_ops->init = _phl_mrc_module_init;
	bk_ops->deinit = _phl_mrc_module_deinit;
	bk_ops->start = _phl_mrc_module_start;
	bk_ops->stop = _phl_mrc_module_stop;
	bk_ops->msg_hdlr = _phl_mrc_module_msg_hdlr;
	bk_ops->set_info = _phl_mrc_module_set_info;
	bk_ops->query_info = _phl_mrc_module_query_info;

	return RTW_PHL_STATUS_SUCCESS;
}
#endif /*CONFIG_CMD_DISP*/
/*
 * init wifi_role control components
 * init band_ctrl
 * init bk module
 * init wifi_role[]
 */
enum rtw_phl_status
phl_mr_ctrl_init(struct phl_info_t *phl_info)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	void *drv = phl_to_drvpriv(phl_info);
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	u8 ridx = MAX_WIFI_ROLE_NUMBER;
	struct rtw_wifi_role_link_t *rlink;
	u8 lidx;
	struct rtw_wifi_role_t *role = NULL;
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;

	mr_ctl->hal_com = rtw_hal_get_halcom(phl_info->hal);
	if (mr_ctl->hal_com == NULL) {
		PHL_ERR("%s mr_ctl->hal_com is NULL\n", __func__);
		_os_warn_on(1);
		return RTW_PHL_STATUS_FAILURE;
	}
	_os_spinlock_init(drv, &(mr_ctl->lock));
	mr_ctl->is_db = false;
	_phl_band_ctrl_init(phl_info);
	#ifdef CONFIG_CMD_DISP
	_phl_role_bk_module_init(phl_info);
	#endif
	_os_mem_set(phl_to_drvpriv(phl_info), phl_com->wifi_roles,
		0, sizeof(*phl_com->wifi_roles));

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		role = &(phl_com->wifi_roles[ridx]);
		pq_init(drv, &role->assoc_mld_queue);
		role->phl_com = phl_com;
		role->id = ridx;
		role->active = false;

		for (lidx = 0; lidx < RTW_RLINK_MAX; lidx++) {
			rlink = get_rlink(role, lidx);
			pq_init(drv, &rlink->assoc_sta_queue);
			rlink->wrole = role;
			rlink->id = lidx;
			rlink->chanctx = NULL;
		}
	}
	#ifdef CONFIG_MCC_SUPPORT
	if (RTW_PHL_STATUS_SUCCESS != (status = rtw_phl_mcc_init(phl_info))) {
		PHL_ERR("%s mcc init fail\n", __func__);
		/* todo, need to discuss with Georgia*/
	}
	#endif
	return RTW_PHL_STATUS_SUCCESS;
}

static enum rtw_phl_status
_phl_band_ctrl_deinit(struct phl_info_t *phl_info)
{
	void *drv = phl_to_drvpriv(phl_info);
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	struct hw_band_ctl_t *band_ctrl;
	u8 band_idx = 0;

	rtw_phl_mcc_deinit(phl_info);
	for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
		band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
		phl_chanctx_free(phl_info, band_ctrl);
		_os_spinlock_free(drv, &(band_ctrl->lock));
		pq_deinit(drv , &band_ctrl->chan_ctx_queue);
	}

	return RTW_PHL_STATUS_SUCCESS;
}

enum rtw_phl_status
phl_mr_ctrl_deinit(struct phl_info_t *phl_info)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	u8 ridx = MAX_WIFI_ROLE_NUMBER;
	struct rtw_wifi_role_t *role;
	void *drv = phl_to_drvpriv(phl_info);
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct rtw_wifi_role_link_t *rlink;
	u8 lidx;

	_os_spinlock_free(drv, &(mr_ctl->lock));
	_phl_band_ctrl_deinit(phl_info);

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		role = &(phl_com->wifi_roles[ridx]);

		pq_deinit(drv, &role->assoc_mld_queue);
		for (lidx = 0; lidx < RTW_RLINK_MAX; lidx++) {
			rlink = get_rlink(role, lidx);
			pq_deinit(drv, &rlink->assoc_sta_queue);
		}
	}

	return RTW_PHL_STATUS_SUCCESS;
}

enum rtw_phl_status
phl_mr_chandef_sync(struct phl_info_t *phl_info, struct hw_band_ctl_t *band_ctrl,
			struct rtw_chan_ctx *chanctx, struct rtw_chan_def *chandef)
{
	void *drv = phl_to_drvpriv(phl_info);
	u8 ridx;
	u8 role_num = 0;
	enum band_type band_ret = BAND_MAX;
	u8 ch_ret = 0;
	enum channel_width bw_ret = CHANNEL_WIDTH_20;
	enum chan_offset offset_ret = CHAN_OFFSET_NO_EXT;
	struct rtw_wifi_role_t *wrole;
	enum rtw_phl_status phl_sts = RTW_PHL_STATUS_FAILURE;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;

	if (!chanctx) {
		PHL_ERR("%s failed, chanctx == NULL\n", __func__);
		goto _exit;
	}
	if (!chandef) {
		PHL_ERR("%s failed, chandef == NULL\n", __func__);
		goto _exit;
	}

	_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (chanctx->role_map & BIT(ridx)) {
			wrole = phl_get_wrole_by_ridx(phl_info, ridx);
			if (wrole == NULL) {
				PHL_ERR("ridx :%d wrole == NULL\n", ridx);
				_os_warn_on(1);
				continue;
			}

			for (idx = 0; idx < wrole->rlink_num; idx++) {
				rlink = get_rlink(wrole, idx);
				if (rlink->hw_band == band_ctrl->id)
					break;
			}
			if (role_num == 0) {
				band_ret = rlink->chandef.band;
				ch_ret = rlink->chandef.chan;
				bw_ret = rlink->chandef.bw;
				offset_ret = rlink->chandef.offset;
				role_num++;
				continue;
			}
			if (band_ret != rlink->chandef.band) {
				PHL_ERR("band_ret(%d) !=  ridx(%d)-band_ret(%d)\n",
					band_ret, ridx, rlink->chandef.band);
				_os_warn_on(1);
				role_num = 0;
				break;
			}
			if (ch_ret !=  rlink->chandef.chan) {
				PHL_ERR("ch_ret(%d) !=  ridx(%d)-chan(%d)\n",
					ch_ret, ridx, rlink->chandef.chan);
				_os_warn_on(1);
				role_num = 0;
				break;
			}

			if (bw_ret < rlink->chandef.bw) {
				bw_ret = rlink->chandef.bw;
				offset_ret = rlink->chandef.offset;
			} else if (bw_ret == rlink->chandef.bw && offset_ret != rlink->chandef.offset) {
				role_num = 0;
				break;
			}

			role_num++;
		}
	}
	_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);

	if (role_num == 0) {
		PHL_ERR("%s role_num=0\n", __func__);
		_os_warn_on(!role_num);
		goto _exit;
	}

	PHL_INFO("%s org_chctx - band:%d, chan:%d, bw:%d, offset:%d\n",
		__func__, chandef->band, chandef->chan, chandef->bw, chandef->offset);
	PHL_INFO("%s mi_upt - band:%d, chan:%d, bw:%d, offset:%d\n",
		__func__, band_ret, ch_ret, bw_ret, offset_ret);

	chandef->band = band_ret;
	chandef->chan = ch_ret;
	chandef->bw = bw_ret;
	chandef->offset = offset_ret;
	phl_sts = RTW_PHL_STATUS_SUCCESS;

_exit:
	return phl_sts;
}

/*
 * MR change chctx from wrole->chdef to new chdef
 * @wrole: specific role, and we can get original chdef.
 * @new_chan: new chdef
 * @chctx_result: The final ch ctx after change new chdef to MR.
 * ex: In the scc case, it will be the group chdef.
 */
enum rtw_phl_status
phl_mr_chandef_chg(struct phl_info_t *phl,
                   struct rtw_wifi_role_t *wrole,
                   struct rtw_wifi_role_link_t *rlink,
                   struct rtw_chan_def *new_chan,
                   struct rtw_chan_def *chctx_result)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
	struct rtw_chan_def chan_def = {0};
	struct rtw_mr_chctx_info mr_cc_info = {0};
	void *drv = phl_to_drvpriv(phl);
	u8 chanctx_num = 0;

	chanctx_num = (u8)rtw_phl_chanctx_del(phl, wrole, rlink, &chan_def);

	_os_mem_cpy(drv, &chan_def, new_chan, sizeof(struct rtw_chan_def));

	if (rtw_phl_chanctx_add((void *)phl, wrole, rlink, &chan_def, &mr_cc_info)) {
		_os_mem_cpy(drv, chctx_result, &chan_def,
				sizeof(struct rtw_chan_def));
		psts = RTW_PHL_STATUS_SUCCESS;
		goto exit;
	}
	PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Add new chandef fail, something wrong!\n",
		__FUNCTION__);
	/* Error handle: Recover the chctx */
	_os_mem_cpy(drv, &chan_def, &rlink->chandef,
			sizeof(struct rtw_chan_def));

	if (!rtw_phl_chanctx_add((void *)phl, wrole, rlink, &chan_def, &mr_cc_info)) {
		PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Error handle failed for recovery!\n",
			__FUNCTION__);
		goto exit;
	}

exit:
	return psts;
}

enum rtw_phl_status
phl_mr_chandef_upt(struct phl_info_t *phl_info,
		struct hw_band_ctl_t *band_ctrl, struct rtw_chan_ctx *chanctx)
{
	enum rtw_phl_status phl_sts = RTW_PHL_STATUS_FAILURE;

	if (!chanctx) {
		PHL_ERR("%s chanctx == NULL\n", __func__);
		goto _exit;
	}

	phl_sts = phl_mr_chandef_sync(phl_info, band_ctrl, chanctx, &chanctx->chan_def);
	if (phl_sts != RTW_PHL_STATUS_SUCCESS)
		PHL_ERR("%s phl_mr_sync_chandef failed\n", __func__);
_exit:
	return phl_sts;
}

enum rtw_phl_status
rtw_phl_mr_upt_chandef(void *phl,
                       struct rtw_wifi_role_link_t *rlink)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
	enum rtw_phl_status phl_sts = RTW_PHL_STATUS_FAILURE;

	if (!rlink->chanctx) {
		PHL_ERR("%s failed - rlink->chanctx == NULL\n", __func__);
		goto _exit;
	}
	phl_sts = phl_mr_chandef_upt(phl_info, band_ctrl, rlink->chanctx);
	if (phl_sts != RTW_PHL_STATUS_SUCCESS)
		PHL_ERR("%s phl_mr_chandef_upt failed\n", __func__);

_exit:
	return phl_sts;
}

int phl_mr_get_chandef_by_band(struct phl_info_t *phl_info,
					enum phl_band_idx band_idx,
					struct rtw_chan_def *chandef)
{
	void *drv = phl_to_drvpriv(phl_info);
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
	struct phl_queue *chan_ctx_queue = &band_ctrl->chan_ctx_queue;
	struct rtw_chan_ctx *chanctx = NULL;
	int chctx_num = 0;
	u8 chctx_role_num = 0;

	if (!chandef) {
		PHL_ERR("%s failed - chandef == NULL\n", __func__);
		return chctx_num;
	}

	/*init chandef*/
	chandef->chan = 0;
	chctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);

	if (chctx_num == 0) {
		PHL_DBG("%s band:%d chctx_num(%d)\n", __func__, band_idx, chctx_num);
	}
	else if (chctx_num == 1) {/*SWR or SCC*/
		_os_spinlock(drv, &chan_ctx_queue->lock, _bh, NULL);
		if (list_empty(&chan_ctx_queue->queue)) {
			PHL_ERR("%s chan_ctx_queue->queue is empty\n", __func__);
			_os_warn_on(1);
		}

		chanctx = list_first_entry(&chan_ctx_queue->queue,
						struct rtw_chan_ctx, list);
		chctx_role_num = phl_chanctx_get_rnum(phl_info, chan_ctx_queue, chanctx);
		if (chctx_role_num == 0) {
			PHL_ERR("%s-%d chctx_role_num == 0\n", __FUNCTION__, __LINE__);
			chctx_num = 0;
			_os_warn_on(1);
		}
		/*chctx_role_num == 1*/
		_os_mem_cpy(drv, chandef, &chanctx->chan_def,
					sizeof(struct rtw_chan_def));
		_os_spinunlock(drv, &chan_ctx_queue->lock, _bh, NULL);
	}
	else if (chctx_num == 2) {/*MCC*/
		PHL_ERR("%s band:%d chctx_num(%d) is not support yet\n",
			__func__, band_idx, chctx_num);
	}
	else {
		PHL_ERR("%s band:%d chctx_num(%d) is invalid\n",
			__func__, band_idx, chctx_num);
		_os_warn_on(1);
	}
	return chctx_num;
}

int rtw_phl_mr_get_chandef_by_hwband(void *phl,
					enum phl_band_idx band_idx,
					struct rtw_chan_def *chandef)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return phl_mr_get_chandef_by_band(phl_info, band_idx, chandef);
}

enum rtw_phl_status
phl_mr_get_chandef(struct phl_info_t *phl_info,
                   struct rtw_wifi_role_t *wifi_role,
                   struct rtw_wifi_role_link_t *rlink,
                   bool sync,
                   struct rtw_chan_def *chandef)
{
	enum rtw_phl_status phl_sts = RTW_PHL_STATUS_SUCCESS;
	void *drv = phl_to_drvpriv(phl_info);
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	u8 hw_band = rlink->hw_band;
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
	struct phl_queue *chan_ctx_queue = &band_ctrl->chan_ctx_queue;
	struct rtw_chan_ctx *chanctx = NULL;
	int chctx_num = 0;
	u8 chctx_role_num = 0;

	if (!chandef) {
		PHL_ERR("%s failed - chandef == NULL\n", __func__);
		phl_sts = RTW_PHL_STATUS_FAILURE;
		goto _exit;
	}

	/*init chandef*/
	chandef->chan = 0;

	if (rlink->chanctx) {
		chctx_role_num = phl_chanctx_get_rnum_with_lock(phl_info, chan_ctx_queue, rlink->chanctx);

		if (chctx_role_num == 0) {
			PHL_ERR("%s-%d chctx_role_num == 0\n", __FUNCTION__, __LINE__);
			_os_warn_on(1);
		}
		if (sync && chctx_role_num >= 2) {
			phl_sts = phl_mr_chandef_sync(phl_info, band_ctrl,
			                              rlink->chanctx, chandef);
			if (phl_sts != RTW_PHL_STATUS_SUCCESS) {
				PHL_ERR("%s phl_mr_chandef_sync failed\n", __func__);
				_os_warn_on(1);
			}
		} else { /*chctx_role_num == 1*/
			_os_mem_cpy(drv, chandef, &rlink->chanctx->chan_def,
			            sizeof(struct rtw_chan_def));
		}
	} else {
		chctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
		if (chctx_num == 0) {
			_os_mem_cpy(drv, chandef, &rlink->chandef,
			            sizeof(struct rtw_chan_def));
		} else if (chctx_num == 1) {
			_os_spinlock(drv, &chan_ctx_queue->lock, _bh, NULL);
			if (list_empty(&chan_ctx_queue->queue)) {
				PHL_ERR("%s chan_ctx_queue->queue is empty\n", __func__);
				_os_warn_on(1);
			}

			chanctx = list_first_entry(&chan_ctx_queue->queue,
						struct rtw_chan_ctx, list);
			chctx_role_num = phl_chanctx_get_rnum(phl_info, chan_ctx_queue, chanctx);
			if (chctx_role_num == 0) {
				PHL_ERR("%s-%d chctx_role_num == 0\n", __FUNCTION__, __LINE__);
				_os_warn_on(1);
			}
			if (sync && chctx_role_num >= 2) {
				phl_sts = phl_mr_chandef_sync(phl_info, band_ctrl,
								chanctx, chandef);
				if (phl_sts != RTW_PHL_STATUS_SUCCESS)
					PHL_ERR("%s phl_mr_chandef_sync failed\n", __func__);
			} else { /*chctx_role_num == 1*/
				_os_mem_cpy(drv, chandef, &chanctx->chan_def,
						sizeof(struct rtw_chan_def));
			}
			_os_spinunlock(drv, &chan_ctx_queue->lock, _bh, NULL);

		} else if (chctx_num == 2) { /*MCC*/

		} else {
			PHL_ERR("%s chctx_num(%d) is invalid\n", __func__, chctx_num);
			_os_warn_on(1);
			goto _exit;
		}
	}

_exit:
	return phl_sts;
}

struct rtw_wifi_role_t *
phl_mr_get_role_by_bandidx(struct phl_info_t *phl_info, u8 band_idx)
{
	struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl_info, band_idx);
	struct rtw_wifi_role_t *wrole = NULL;
	u8 i;
	u8 rnum = 0;

	rnum = phl_mr_get_role_num(phl_info, band_ctrl);
	if (rnum == 0) {
		PHL_ERR("%s B(%d) role number == 0\n", __func__, band_ctrl->id);
		goto _exit;
	}

	for (i = 0; i < MAX_WIFI_ROLE_NUMBER; i++) {
		if (band_ctrl->role_map & BIT(i)) {
			wrole = phl_get_wrole_by_ridx(phl_info, i);
			if (wrole->active == true)
				break;
			else
				wrole = NULL;
		}
	}

_exit :
	if (wrole == NULL) {
		PHL_ERR("%s B(%d) cannot get wrole\n", __func__, band_ctrl->id);
		/*_os_warn_on(1);*/
	}
	return wrole;
}

enum rtw_phl_status
rtw_phl_mr_get_chandef(void *phl,
                       struct rtw_wifi_role_t *wifi_role,
                       struct rtw_wifi_role_link_t *rlink,
                       struct rtw_chan_def *chandef)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return phl_mr_get_chandef(phl_info, wifi_role, rlink, false, chandef);
}
int rtw_phl_mr_get_chanctx_num(void *phl,
                               struct rtw_wifi_role_t *wifi_role,
                               struct rtw_wifi_role_link_t *rlink)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	u8 band_idx = rlink->hw_band;
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);

	return phl_mr_get_chanctx_num(phl_info, band_ctrl);
}

enum rtw_phl_status
rtw_phl_mr_rx_filter_opt(void *phl, struct rtw_wifi_role_link_t *rlink)
{
	/* Not switch RX filter according to role for AP applications. */
#if !defined(PHL_FEATURE_AP)
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	enum rtw_rx_fltr_opt_mode mode = RX_FLTR_OPT_MODE_STA_NORMAL;
#ifdef CONFIG_MR_SUPPORT
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);

	if (band_ctrl->cur_info.p2p_device_num >= 1 &&
	    band_ctrl->cur_info.lsn_discov)
		mode = RX_FLTR_OPT_MODE_LSN_DISCOV;
	else if (band_ctrl->cur_info.lg_sta_num >= 1)
		mode = RX_FLTR_OPT_MODE_STA_LINKING;
	else if (band_ctrl->cur_info.ap_num >= 1)
		mode = RX_FLTR_OPT_MODE_AP_NORMAL;
	else if (band_ctrl->cur_info.ld_sta_num >= 1)
		mode = RX_FLTR_OPT_MODE_STA_NORMAL;	/* Accpet BSSID matched frames */
	else
		mode = RX_FLTR_OPT_MODE_STA_NORMAL; /* For STA no link case */

#else
	struct rtw_wifi_role_t *wrole = rlink->wrole;
	if (rtw_phl_role_is_client_category(wrole) && wrole->mstate == MLME_LINKED)
		mode = RX_FLTR_OPT_MODE_STA_NORMAL;
	else if (rtw_phl_role_is_client_category(wrole) && wrole->mstate == MLME_LINKING)
		mode = RX_FLTR_OPT_MODE_STA_LINKING;
	else if (rtw_phl_role_is_ap_category(wrole))
		mode = RX_FLTR_OPT_MODE_AP_NORMAL;
	else
		mode = RX_FLTR_OPT_MODE_STA_NORMAL;/* For STA no link case */

#endif /*CONFIG_MR_SUPPORT*/

	rtw_hal_set_rxfltr_opt_by_mode(phl_info->hal, rlink->hw_band, mode);
#endif /* !PHL_AP_FEATURE */
	return RTW_PHL_STATUS_SUCCESS;
}

/**
 * The decision rule of updating *trgt_cur by comparing with trgt_chk:
 * (chk = trgt_chk, cur = *trgt_cur, fnl = final decision of *trgt_cur)
 * (D = DROP, H = TO_HOST, W = TO_WLCPU)
 *
 *
 *	    |		cur
 *    fnl   |---------------------------
 *	    |	D	H	W
 * -------------------------------------
 *	| D |	D	H	W
 *	|   |
 *  chk	| H |	H	H	W
 *	|   |
 *	| W |	W	W	W
 */
static void _phl_mr_rxfltr_target_dcsn(enum rtw_rxfltr_target trgt_chk,
				       enum rtw_rxfltr_target *trgt_cur)
{
	switch (trgt_chk) {
	case RXFLTR_TARGET_DROP:
		break;
	case RXFLTR_TARGET_TO_HOST:
		if (*trgt_cur == RXFLTR_TARGET_DROP)
			*trgt_cur = RXFLTR_TARGET_TO_HOST;

		break;
	case RXFLTR_TARGET_TO_WLCPU:
		*trgt_cur = RXFLTR_TARGET_TO_WLCPU;
		break;
	case RXFLTR_TARGET_MAX:
	default:
		break;
	}
}

static void _phl_mr_rxfltr_target_dcsn_ctrl(struct rxfltr_cap_ctrl *cap_chk,
					    struct rxfltr_cap_to_set_ctrl *cap_cur)
{
	u8 i = 0;

	for (i = 0; i < RXFLTR_STYPE_CTRL_MAX; i++) {
		if (cap_cur->stype[i].set == false)
			continue;

		_phl_mr_rxfltr_target_dcsn(cap_chk->stype[i].target,
					   &(cap_cur->stype[i].target));
	}
}

static void _phl_mr_rxfltr_target_dcsn_mgnt(struct rxfltr_cap_mgnt *cap_chk,
					    struct rxfltr_cap_to_set_mgnt *cap_cur)
{
	u8 i = 0;

	for (i = 0; i < RXFLTR_STYPE_MGNT_MAX; i++) {
		if (cap_cur->stype[i].set == false)
			continue;

		_phl_mr_rxfltr_target_dcsn(cap_chk->stype[i].target,
					   &(cap_cur->stype[i].target));
	}
}

static void _phl_mr_rxfltr_target_dcsn_data(struct rxfltr_cap_data *cap_chk,
					    struct rxfltr_cap_to_set_data *cap_cur)
{
	u8 i = 0;

	for (i = 0; i < RXFLTR_STYPE_DATA_MAX; i++) {
		if (cap_cur->stype[i].set == false)
			continue;

		_phl_mr_rxfltr_target_dcsn(cap_chk->stype[i].target,
					   &(cap_cur->stype[i].target));
	}
}

static void _phl_mr_rx_filter_type(struct phl_info_t *phl_info,
				   struct rtw_wifi_role_link_t *rlink,
				   struct rxfltr_type_cap_to_set *cap_s)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
	u8 role_map = band_ctrl->role_map;
	struct rtw_wifi_role_t *wr = NULL;
	struct rxfltr_type_cap *cap_rlink = NULL;
	u8 ridx = 0, lidx = 0;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		/* only consider allocated role on the same band */
		if (!(role_map & BIT(ridx)))
			continue;

		wr = &(phl_com->wifi_roles[ridx]);

		/* exclude inactive role */
		if (wr->active == false)
			continue;

		for (lidx = 0; lidx < wr->rlink_num; lidx++) {
			/* only consider rlink on the same hw_band */
			if (wr->rlink[lidx].hw_band != rlink->hw_band)
				continue;

			/* exclude self rlink */
			if ((wr->id == rlink->wrole->id) && (wr->rlink[lidx].id == rlink->id))
				continue;

			cap_rlink = &(wr->rlink[lidx].rxfltr_type_cap);

			_phl_mr_rxfltr_target_dcsn_ctrl(&(cap_rlink->rxfltr_ctrl),
							&(cap_s->rxfltr_ctrl));
			_phl_mr_rxfltr_target_dcsn_mgnt(&(cap_rlink->rxfltr_mgnt),
							&(cap_s->rxfltr_mgnt));
			_phl_mr_rxfltr_target_dcsn_data(&(cap_rlink->rxfltr_data),
							&(cap_s->rxfltr_data));
		}
	}
}

#define PHL_MR_SET_RXFLTR_STYPE_CTRL(s, t, cr, cs)	\
	do { \
		(cr)->rxfltr_ctrl.stype[s].target = t; \
		(cs)->rxfltr_ctrl.stype[s].set = true; \
		(cs)->rxfltr_ctrl.stype[s].target = t; \
	} while (0)
#define PHL_MR_SET_RXFLTR_STYPE_MGNT(s, t, cr, cs)	\
	do { \
		(cr)->rxfltr_mgnt.stype[s].target = t; \
		(cs)->rxfltr_mgnt.stype[s].set = true; \
		(cs)->rxfltr_mgnt.stype[s].target = t; \
	} while (0)
#define PHL_MR_SET_RXFLTR_STYPE_DATA(s, t, cr, cs)	\
	do { \
		(cr)->rxfltr_data.stype[s].target = t; \
		(cs)->rxfltr_data.stype[s].set = true; \
		(cs)->rxfltr_data.stype[s].target = t; \
	} while (0)

static void _phl_mr_set_rxfltr_cap_by_type(u8 type, u8 target, struct rxfltr_type_cap *cap_rxfltr,
					   struct rxfltr_type_cap_to_set *cap_rxfltr_s)
{
	u8 i = 0;

	switch (type) {
	case RTW_PHL_PKT_TYPE_CTRL:
		for (i = 0; i < RXFLTR_STYPE_CTRL_MAX; i++)
			PHL_MR_SET_RXFLTR_STYPE_CTRL(i, target, cap_rxfltr, cap_rxfltr_s);

		break;
	case RTW_PHL_PKT_TYPE_MGNT:
		for (i = 0; i < RXFLTR_STYPE_MGNT_MAX; i++)
			PHL_MR_SET_RXFLTR_STYPE_MGNT(i, target, cap_rxfltr, cap_rxfltr_s);

		break;
	case RTW_PHL_PKT_TYPE_DATA:
		for (i = 0; i < RXFLTR_STYPE_DATA_MAX; i++)
			PHL_MR_SET_RXFLTR_STYPE_DATA(i, target, cap_rxfltr, cap_rxfltr_s);

		break;
	}
}

#define PHL_MR_SET_RXFLTR_TYPE_CTRL(t, cr, cs)	\
	_phl_mr_set_rxfltr_cap_by_type(RTW_PHL_PKT_TYPE_CTRL, t, cr, cs)
#define PHL_MR_SET_RXFLTR_TYPE_MGNT(t, cr ,cs)	\
	_phl_mr_set_rxfltr_cap_by_type(RTW_PHL_PKT_TYPE_MGNT, t, cr, cs)
#define PHL_MR_SET_RXFLTR_TYPE_DATA(t, cr, cs)	\
	_phl_mr_set_rxfltr_cap_by_type(RTW_PHL_PKT_TYPE_DATA, t, cr, cs)

enum rtw_phl_status rtw_phl_mr_set_rxfltr_type_by_mode(void *phl, struct rtw_wifi_role_link_t *rlink,
						       enum rtw_rxfltr_type_mode mode)
{
	struct phl_info_t *phl_info = (struct phl_info_t*)phl;
	struct rxfltr_type_cap *cap_rlink = NULL;
	struct rxfltr_type_cap_to_set cap_rlink_set = {0};
	enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE;

	cap_rlink = &(rlink->rxfltr_type_cap);

	/* set rxfltr type cap of this role link by mode */
	switch (mode) {
	case RX_FLTR_TYPE_MODE_MONITOR:
		PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
		PHL_MR_SET_RXFLTR_TYPE_MGNT(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
		PHL_MR_SET_RXFLTR_TYPE_DATA(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
		break;
	case RX_FLTR_TYPE_MODE_ROLE_INIT:
		PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
		PHL_MR_SET_RXFLTR_TYPE_MGNT(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
		PHL_MR_SET_RXFLTR_TYPE_DATA(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
		break;
	case RX_FLTR_TYPE_MODE_STA_CONN:
		PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_VHT_HE_NDPA, RXFLTR_TARGET_TO_HOST,
					     cap_rlink, &cap_rlink_set);
		PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_BAR, RXFLTR_TARGET_TO_HOST,
					     cap_rlink, &cap_rlink_set);
#ifdef RTW_WKARD_RX_FLTR_HE_TF
		if (rlink->cap.wmode & WLAN_MD_11AX) {
			PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_TRIGGER, RXFLTR_TARGET_TO_HOST,
						     cap_rlink, &cap_rlink_set);
		}
#endif
		break;
	case RX_FLTR_TYPE_MODE_STA_DIS_CONN:
		PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
		break;
	case RX_FLTR_TYPE_MODE_AP_CONN:
		PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_VHT_HE_NDPA, RXFLTR_TARGET_TO_HOST,
					     cap_rlink, &cap_rlink_set);
		PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_BAR, RXFLTR_TARGET_TO_HOST,
					     cap_rlink, &cap_rlink_set);
		PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_PS_POLL, RXFLTR_TARGET_TO_HOST,
					     cap_rlink, &cap_rlink_set);
		break;
	case RX_FLTR_TYPE_MODE_AP_DIS_CONN:
		if (rlink->assoc_sta_queue.cnt < 2)
			PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
		break;

#ifdef CONFIG_PHL_CHANNEL_INFO
	case RX_FLTR_TYPE_MODE_CHAN_INFO_EN:
		PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_ACK, RXFLTR_TARGET_TO_HOST,
					     cap_rlink, &cap_rlink_set);
	break;
	case RX_FLTR_TYPE_MODE_CHAN_INFO_DIS:
		PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
	break;
#endif
	default:
		PHL_TRACE(COMP_PHL_RECV, _PHL_ERR_, "%s: does not handle rxfltr mode(%u)\n", __func__, mode);
		return RTW_PHL_STATUS_FAILURE;
	}

	/* jointly decide rxfltr type cap among all active rlinks */
	_phl_mr_rx_filter_type(phl_info, rlink, &cap_rlink_set);

	/* call HAL API to set rxfltr type cap */
	hsts = rtw_hal_set_rxfltr_by_stype_all(phl_info->hal, rlink->hw_band, &cap_rlink_set);

	return (hsts == RTW_HAL_STATUS_SUCCESS) ? RTW_PHL_STATUS_SUCCESS : RTW_PHL_STATUS_FAILURE;
}

enum rtw_phl_status phl_mr_tsf_sync(void *phl,
                                    struct rtw_wifi_role_t *wrole,
                                    struct rtw_wifi_role_link_t *rlink,
                                    enum role_state state)
{
	enum rtw_phl_status ret = RTW_PHL_STATUS_SUCCESS;
#ifdef CONFIG_MR_SUPPORT
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	void *drv = phl_to_drvpriv(phl_info);
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	enum phl_band_idx band = rlink->hw_band;
	struct hw_band_ctl_t *band_ctl = &mr_ctl->band_ctrl[band];
	struct rtw_chan_ctx *chanctx = rlink->chanctx;
	struct rtw_phl_com_t *phl_com = wrole->phl_com;
	struct rtw_wifi_role_t *check_wr = NULL;
	struct rtw_wifi_role_t *ld_sta_wr = NULL;
	struct rtw_wifi_role_link_t *wrl_sync_from = NULL;
	struct rtw_wifi_role_link_t *wrl_sync_to = NULL;
	s8 tsf_sync_offset_tu = PHL_MR_TSF_SYNC_BASE_OFFSET; /* unit is TU(1024us) */
	u8 tsf_offset_range_rand = 0;
	u8 ridx = 0, lidx = 0;
	u8 ap_num = band_ctl->cur_info.ap_num;
	u8 ld_sta_num = band_ctl->cur_info.ld_sta_num;
	int chanctx_num = 0;

	tsf_offset_range_rand = _os_random32(drv) % (2 * PHL_MR_TSF_SYNC_OFFSET_RANGE + 1);
	if (tsf_offset_range_rand != 0) {
		if (tsf_offset_range_rand > PHL_MR_TSF_SYNC_OFFSET_RANGE)
			tsf_sync_offset_tu -= (tsf_offset_range_rand - PHL_MR_TSF_SYNC_OFFSET_RANGE);
		else
			tsf_sync_offset_tu += tsf_offset_range_rand;
	}

	chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctl);
	PHL_INFO("%s:state(%d), ap_num=%d, ld_sta_num=%d, tsf_sync_port=%d,chanctx_num=%d\n",
			__func__, state, ap_num, ld_sta_num, band_ctl->tsf_sync_port, chanctx_num);

	#ifdef CONFIG_MCC_SUPPORT
	if (chanctx_num > 1) {
		if (phl_com->dev_cap.mcc_sup == true) {
			PHL_INFO("%s: will process MCC, skip tsf sync\n", __func__);
			ret = RTW_PHL_STATUS_SUCCESS;
			goto exit;
		} else {
			PHL_ERR("%s: chanctx_num(%d) > 1, check chanctx\n", __func__, chanctx_num);
			ret = RTW_PHL_STATUS_FAILURE;
			goto exit;
		}
	}
	#endif

	switch (state) {
	case PHL_ROLE_MSTS_STA_CONN_END:
		if (chanctx == NULL) {
			PHL_WARN("%s: state%d wifi role (id=%d) role link (id=%d) chanctx=NULL\n", __func__, state, wrole->id, rlink->id);
			ret = RTW_PHL_STATUS_FAILURE;
			goto exit;
		}
		/* SoftAP already started, and no tsf sync before */
		if (ap_num >= 1 && band_ctl->tsf_sync_port == HW_PORT_MAX) {
			/* tsf sync for all softap */
			wrl_sync_from = rlink;
			for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
				if (chanctx->role_map & BIT(ridx)) {
					check_wr = &phl_com->wifi_roles[ridx];
					/* Get role link from another role within the same chanctx */
					for (lidx = 0; lidx < check_wr->rlink_num; lidx++) {
						wrl_sync_to = get_rlink(check_wr, lidx);
						if (wrl_sync_to->hw_band == band)
							break;
					}
					if (lidx == check_wr->rlink_num) {
						PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
						ret = RTW_PHL_STATUS_FAILURE;
						goto exit;
					}

					if (wrole != check_wr) {
						switch (check_wr->type) {
						case PHL_RTYPE_AP:
						case PHL_RTYPE_VAP:
						case PHL_RTYPE_P2P_GO:
						case PHL_RTYPE_MESH:
							if (rtw_hal_tsf_sync(phl_info->hal, wrl_sync_from->hw_port,
								wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
								ret = RTW_PHL_STATUS_SUCCESS;
								PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) success\n",
									__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
									wrole->id, wrl_sync_from->id, wrl_sync_from->hw_port);
							} else {
								ret = RTW_PHL_STATUS_FAILURE;
								PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) fail\n",
									__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
									wrole->id, wrl_sync_from->id, wrl_sync_from->hw_port);
								break;
							}
							break;
						default :
							break;
						}
					}
				}
			}

			if (ret == RTW_PHL_STATUS_SUCCESS)
				band_ctl->tsf_sync_port = wrl_sync_from->hw_port;
			else
				band_ctl->tsf_sync_port = HW_PORT_MAX;
		}
		break;
	case PHL_ROLE_MSTS_STA_DIS_CONN:
		/* if TSF sync do not enable, skip disable flow */
		if (band_ctl->tsf_sync_port == HW_PORT_MAX) {
			ret = RTW_PHL_STATUS_SUCCESS;
			goto exit;
		}

		if (chanctx == NULL) {
			PHL_WARN("%s: state(%d) wifi role (id=%d) role link (id=%d) chanctx=NULL\n",
				__func__, state, wrole->id, rlink->id);
			ret = RTW_PHL_STATUS_FAILURE;
			goto exit;
		}

		/* if disconnected STA is sync port and SoftAP exists,
		find new sync port */
		if (rlink->hw_port == band_ctl->tsf_sync_port &&
			ap_num >= 1 && ld_sta_num > 0) {
			/* find linked sta */
			ld_sta_wr = _search_ld_sta_wrole(wrole, rlink, true);

			if (ld_sta_wr) {
				/* Get role link from ld_sta_wr within the same hw band */
				for (lidx = 0; lidx < ld_sta_wr->rlink_num; lidx++) {
					wrl_sync_from = get_rlink(ld_sta_wr, lidx);
					if (wrl_sync_from->hw_band == band)
						break;
				}
				if (lidx == ld_sta_wr->rlink_num) {
					PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
					ret = RTW_PHL_STATUS_FAILURE;
					goto exit;
				}

				/* re-sync tsf for all softap */
				for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
					if (chanctx->role_map & BIT(ridx)) {
						check_wr = &phl_com->wifi_roles[ridx];

						check_wr = &phl_com->wifi_roles[ridx];
						/* Get role link from another role within the same chanctx */
						for (lidx = 0; lidx < check_wr->rlink_num; lidx++) {
							wrl_sync_to = get_rlink(check_wr, lidx);
							if (wrl_sync_to->hw_band == band)
								break;
						}
						if (lidx == check_wr->rlink_num) {
							PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
							ret = RTW_PHL_STATUS_FAILURE;
							goto exit;
						}
						if (ld_sta_wr != check_wr) {
							switch (check_wr->type) {
							case PHL_RTYPE_AP:
							case PHL_RTYPE_VAP:
							case PHL_RTYPE_P2P_GO:
							case PHL_RTYPE_MESH:
								if (rtw_hal_tsf_sync(phl_info->hal, wrl_sync_from->hw_port,
									wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
									ret = RTW_PHL_STATUS_SUCCESS;
									PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) success\n",
										 __func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
										 ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
								} else {
									ret = RTW_PHL_STATUS_FAILURE;
									PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) fail\n",
										 __func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
										 ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
									break;
								}
								break;
							default :
								break;
							}
						}
					}
				}

				if (ret == RTW_PHL_STATUS_SUCCESS)
					band_ctl->tsf_sync_port = wrl_sync_from->hw_port;
				else
					band_ctl->tsf_sync_port = HW_PORT_MAX;
			}
		}

		/* if disconnected STA is sync port and no other linked sta exist,
		disable sofap tsf sync */
		if (rlink->hw_port == band_ctl->tsf_sync_port && ld_sta_num == 0) {
			for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
				if (chanctx->role_map & BIT(ridx)){
					check_wr = &phl_com->wifi_roles[ridx];

					/* Get role link from another role within the same chanctx */
					for (lidx = 0; lidx < check_wr->rlink_num; lidx++) {
						wrl_sync_to = get_rlink(check_wr, lidx);
						if (wrl_sync_to->hw_band == band)
							break;
					}
					if (lidx == check_wr->rlink_num) {
						PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
						ret = RTW_PHL_STATUS_FAILURE;
						goto exit;
					}
					if (wrole != check_wr) {
						switch (check_wr->type) {
						case PHL_RTYPE_AP:
						case PHL_RTYPE_VAP:
						case PHL_RTYPE_P2P_GO:
						case PHL_RTYPE_MESH:
							if (check_wr->mstate == MLME_LINKED) {
								if (rtw_hal_tsf_sync(phl_info->hal, band_ctl->tsf_sync_port,
									wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_DIS_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
									ret = RTW_PHL_STATUS_SUCCESS;
									PHL_INFO("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole (port:%d) success\n",
										__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
										band_ctl->tsf_sync_port);
								} else {
									ret = RTW_PHL_STATUS_FAILURE;
									PHL_ERR("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole:(port:%d) fail\n",
										__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
										band_ctl->tsf_sync_port);
									break;
								}
							}
							break;
						default :
							break;
						}
					}
				}
			}

			if (ret == RTW_PHL_STATUS_SUCCESS)
				band_ctl->tsf_sync_port = HW_PORT_MAX;
		}
		break;
	case PHL_ROLE_MSTS_AP_START:
		if (chanctx == NULL) {
			PHL_WARN("%s: state%d wifi role (id=%d) rlink (id=%d)chanctx=NULL\n", __func__, state, wrole->id, rlink->id);
			ret = RTW_PHL_STATUS_FAILURE;
			goto exit;
		}
		/* no linked sta, don't enable tsf sync */
		if (ld_sta_num == 0) {
			ret = RTW_PHL_STATUS_SUCCESS;
			goto exit;
		}
		/* New softAP start, and no tsf sync before, find sync port  */
		if (band_ctl->tsf_sync_port == HW_PORT_MAX) {
			wrl_sync_to = rlink;
			ld_sta_wr = _search_ld_sta_wrole(wrole, rlink, true);
			if (ld_sta_wr) {
				/* Get role link from ld_sta_wr within the same hw band */
				for (lidx = 0; lidx < ld_sta_wr->rlink_num; lidx++) {
					wrl_sync_from = get_rlink(ld_sta_wr, lidx);
					if (wrl_sync_from->hw_band == band)
						break;
				}
				if (lidx == ld_sta_wr->rlink_num) {
					PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
					ret = RTW_PHL_STATUS_FAILURE;
					goto exit;
				}
				if (rtw_hal_tsf_sync(phl_info->hal, wrl_sync_from->hw_port,
					wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
					band_ctl->tsf_sync_port = wrl_sync_from->hw_port;
					ret = RTW_PHL_STATUS_SUCCESS;
					PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) success\n",
						__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
						ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
				} else {
					ret = RTW_PHL_STATUS_FAILURE;
					PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) fail\n",
						__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
						ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
				}
			}
		} else if (band_ctl->tsf_sync_port != HW_PORT_MAX) {
			/* New softAP start, enable tsf sync before, follow original sync port  */
			wrl_sync_to = rlink;
			if (rtw_hal_tsf_sync(phl_info->hal, band_ctl->tsf_sync_port,
				wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
				ret = RTW_PHL_STATUS_SUCCESS;
				PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) success\n",
					__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
					band_ctl->tsf_sync_port);
			} else {
				ret = RTW_PHL_STATUS_FAILURE;
				PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) fail\n",
					__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
					band_ctl->tsf_sync_port);
			}
		}
		break;
	case PHL_ROLE_MSTS_AP_STOP:
		/* if TSF sync do not enable, skip disable flow */
		if (band_ctl->tsf_sync_port == HW_PORT_MAX) {
			ret = RTW_PHL_STATUS_SUCCESS;
			goto exit;
		}
		wrl_sync_to = rlink;
		if (rtw_hal_tsf_sync(phl_info->hal, band_ctl->tsf_sync_port,
					wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_DIS_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
			ret = RTW_PHL_STATUS_SUCCESS;
			PHL_INFO("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) success\n",
				__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
				band_ctl->tsf_sync_port);
		} else {
			ret = RTW_PHL_STATUS_FAILURE;
			PHL_ERR("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) fail\n",
				__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
				band_ctl->tsf_sync_port);
		}

		if (ap_num == 0)
			band_ctl->tsf_sync_port = HW_PORT_MAX;
		break;
	default:
		PHL_ERR("%s unsupport state(%d)\n", __func__, state);
		ret = RTW_PHL_STATUS_FAILURE;
		break;
	}

exit:
#endif
	return ret;
}

#ifdef CONFIG_FSM
enum rtw_phl_status
rtw_phl_mr_offch_hdl(void *phl,
		     struct rtw_wifi_role_t *wrole,
		     bool off_ch,
		     void *obj_priv,
		     bool (*issue_null_data)(void *priv, u8 ridx, bool ps),
		     struct rtw_chan_def *chandef)
{
	return RTW_PHL_STATUS_SUCCESS;
}
#endif

void phl_mr_stop_all_beacon(struct phl_info_t *phl_info,
                            struct rtw_wifi_role_t *wrole,
                            u8 band_idx,
                            bool stop)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
	u8 role_map = band_ctrl->role_map;
	struct rtw_wifi_role_t *wr = NULL;
	u8 ridx;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (role_map & BIT(ridx)) {
			wr = &(phl_com->wifi_roles[ridx]);


			if (rtw_phl_role_is_ap_category(wr) ||
			   (wr->type == PHL_RTYPE_MESH)){
				for (idx = 0; idx < wr->rlink_num; idx++) {
					rlink = get_rlink(wr, idx);
					if (rlink->hw_band != band_idx)
						continue;
					rtw_hal_beacon_stop(phl_info->hal, rlink,
						RLINK_BCN_STOP_RSON_DEFAULT, stop);
				}
			}
		}
	}
}

#ifdef DBG_PHL_MR
enum rtw_phl_status
phl_mr_info_dbg(struct phl_info_t *phl_info)
{
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	u8 ridx = MAX_WIFI_ROLE_NUMBER;
	u8 bidx = 0;
	int chanctx_num = 0;
	struct rtw_wifi_role_t *role = NULL;
	struct hw_band_ctl_t *band_ctrl = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 idx = 0;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		role = &(phl_com->wifi_roles[ridx]);

		for (idx = 0; idx < role->rlink_num; idx++) {
			rlink = get_rlink(role, idx);

			if (rlink->assoc_sta_queue.cnt) {
				PHL_DUMP_STACTRL_EX(phl_info);
				PHL_ERR("role_idx:%d link_idx: %d assoc_sta_queue(%d) not empty!\n",
					ridx, idx, rlink->assoc_sta_queue.cnt);
				_os_warn_on(1);
			}
		}
	}
	for (bidx = 0; bidx < MAX_BAND_NUM; bidx++) {
		band_ctrl = &(mr_ctl->band_ctrl[bidx]);
		chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
		if (chanctx_num)
			PHL_ERR("band_idx:%d chanctx_num(%d) not empty!\n", bidx, chanctx_num);
	}

	return RTW_PHL_STATUS_SUCCESS;
}
#endif

enum rtw_phl_status
phl_mr_info_upt(struct phl_info_t *phl_info, struct rtw_wifi_role_link_t *rlink)
{
	void *drv = phl_to_drvpriv(phl_info);
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
	u8 role_map = band_ctrl->role_map;
	struct rtw_wifi_role_t *wr = NULL;
	u8 ridx;

	_os_mem_set(drv, &band_ctrl->cur_info, 0, sizeof(struct mr_info));

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (!(role_map & BIT(ridx)))
			continue;
		wr = &(phl_com->wifi_roles[ridx]);

		switch (wr->type) {
		case PHL_RTYPE_STATION:
		case PHL_RTYPE_P2P_GC:
		case PHL_RTYPE_P2P_DEVICE:
		case PHL_RTYPE_TDLS:
			band_ctrl->cur_info.sta_num++;
			if (wr->mstate == MLME_LINKED)
				band_ctrl->cur_info.ld_sta_num++;
			if (wr->mstate == MLME_LINKING)
				band_ctrl->cur_info.lg_sta_num++;
			if (wr->type == PHL_RTYPE_P2P_GC)
				band_ctrl->cur_info.p2p_gc_num++;
			if (wr->type == PHL_RTYPE_P2P_DEVICE) {
				band_ctrl->cur_info.p2p_device_num++;
				if (TEST_STATUS_FLAG(wr->status, WR_STATUS_LSN_DISCOV))
					band_ctrl->cur_info.lsn_discov = true;
			}
		#ifdef CONFIG_PHL_TDLS
			if (wr->type == PHL_RTYPE_TDLS)
				band_ctrl->cur_info.ld_tdls_num++;
		#endif
			break;

		case PHL_RTYPE_AP:
		case PHL_RTYPE_VAP:
		case PHL_RTYPE_P2P_GO:
		case PHL_RTYPE_MESH:
			if (wr->mstate == MLME_LINKED)
				band_ctrl->cur_info.ap_num++;
			if (wr->assoc_mld_queue.cnt >= 2)
				band_ctrl->cur_info.ld_ap_num++;
			if (wr->type == PHL_RTYPE_P2P_GO)
				band_ctrl->cur_info.p2p_go_num++;
			break;

		case PHL_RTYPE_MONITOR:
			band_ctrl->cur_info.monitor_num++;
			break;

		case PHL_RTYPE_ADHOC:
		case PHL_RTYPE_ADHOC_MASTER:
		case PHL_RTYPE_NAN:
		default :
			break;
		}
	}
	if(band_ctrl->op_mode == MR_OP_SCC ||
	   band_ctrl->op_mode == MR_OP_MCC){
		if(band_ctrl->cur_info.ld_sta_num && band_ctrl->cur_info.ap_num)
			band_ctrl->op_type = MR_OP_TYPE_STATION_AP;
		else if(band_ctrl->cur_info.ld_sta_num)
			band_ctrl->op_type = MR_OP_TYPE_STATION_ONLY;
		else
			band_ctrl->op_type = MR_OP_TYPE_STATION_AP;
	}
	else{
		band_ctrl->op_type = MR_OP_TYPE_NONE;
	}
	/*dump mr_info*/
	PHL_INFO("%s sta_num:%d, ld_sta_num:%d, lg_sta_num:%d\n",
		__func__, band_ctrl->cur_info.sta_num,
		band_ctrl->cur_info.ld_sta_num, band_ctrl->cur_info.lg_sta_num);
#ifdef CONFIG_PHL_TDLS
	PHL_INFO("%s ld_tdls_num:%d\n", __func__, band_ctrl->cur_info.ld_tdls_num);
#endif
	PHL_INFO("%s ap_num:%d, ld_ap_num:%d\n",
		__func__, band_ctrl->cur_info.ap_num, band_ctrl->cur_info.ld_ap_num);
	PHL_INFO("%s p2p_device_num:%d, lsn_discov:%d\n",
	        __func__, band_ctrl->cur_info.p2p_device_num,
	        band_ctrl->cur_info.lsn_discov);
	PHL_INFO("%s op mode:%d op type:%d\n",
		__func__, band_ctrl->op_mode, band_ctrl->op_type);
	return RTW_PHL_STATUS_SUCCESS;
}

enum rtw_phl_status phl_mr_watchdog(struct phl_info_t *phl_info)
{
	enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
#if defined(CONFIG_MR_SUPPORT) &&  defined(CONFIG_MCC_SUPPORT)
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	u8 band_idx = 0;
	int chanctx_num = 0;
	struct hw_band_ctl_t *band_ctrl = NULL;
	#if 0
	struct rtw_chan_ctx *chanctx = NULL;
	void *drv = phl_to_drvpriv(phl_info);
	struct rtw_wifi_role_t *wr = NULL;
	#endif

	for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
		band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
		chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
		if (chanctx_num == 0)
			continue;

		#if 0
		_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
		phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {
			for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
				if (chanctx->role_map & BIT(ridx)) {
					wr = &phl_com->wifi_roles[ridx];
					if(wr->type == PHL_RTYPE_STATION) {
						/*Sounding check*/
						/*phl_snd_watchdog(phl_info, wr);*/
					}
				}
			}
		}
		_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
		#endif

		if (chanctx_num == 2)
			rtw_phl_mcc_watchdog(phl_info, band_idx);
	}
#endif /*CONFIG_MCC_SUPPORT*/
	return psts;
}

static inline u8
__phl_mr_process(struct rtw_wifi_role_t *wrole,
		u8 role_map, bool exclude_self, void *data,
		u8(*ops_func)(struct rtw_wifi_role_t *wrole, void *data))
{
	u8 ridx = 0;
	u8 ret = 0;
	struct rtw_phl_com_t *phl_com = wrole->phl_com;
	struct rtw_wifi_role_t *wr = NULL;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (role_map & BIT(ridx)) {
			wr = &phl_com->wifi_roles[ridx];
			_os_warn_on(!wr->active);
			if ((exclude_self) && (wr == wrole))
				continue;
			if (ops_func)
				if (true == ops_func(wr, data))
					ret++;
		}
	}
	return ret;
}

static u8 _phl_mr_process_by_mrc(struct phl_info_t *phl_info,
		struct rtw_wifi_role_t *wrole, bool exclude_self, void *data,
		u8(*ops_func)(struct rtw_wifi_role_t *wrole, void *data))
{
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(wrole->phl_com);

	return __phl_mr_process(wrole, mr_ctl->role_map, exclude_self, data, ops_func);
}

static u8 _phl_mr_process_by_band(struct phl_info_t *phl_info,
                                  struct rtw_wifi_role_t *wrole,
                                  enum phl_band_idx band_idx,
                                  bool exclude_self,
                                  void *data,
                                  u8(*ops_func)(struct rtw_wifi_role_t *wrole,
                                                void *data))
{
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);

	return __phl_mr_process(wrole, band_ctrl->role_map, exclude_self, data, ops_func);
}

static u8 _phl_mr_process_by_chctx(struct phl_info_t *phl_info,
                                   struct rtw_wifi_role_t *wrole,
                                   struct rtw_wifi_role_link_t *rlink,
                                   bool exclude_self,
                                   void *data,
                                   u8(*ops_func)(struct rtw_wifi_role_t *wrole, void *data))
{
	struct rtw_chan_ctx *chanctx = rlink->chanctx;

	if (!chanctx)
		return 0;
	return __phl_mr_process(wrole, chanctx->role_map, exclude_self, data, ops_func);
}

static u8 _phl_mr_dump_mac_addr(struct rtw_wifi_role_t *wrole, void *data)
{
	PHL_INFO("RIDX:%d - MAC-Addr:%02x-%02x-%02x-%02x-%02x-%02x\n",
			wrole->id, wrole->mac_addr[0], wrole->mac_addr[1], wrole->mac_addr[2],
			wrole->mac_addr[3], wrole->mac_addr[4], wrole->mac_addr[5]);
	return true;
}
u8 rtw_phl_mr_dump_mac_addr(void *phl,
					struct rtw_wifi_role_t *wifi_role)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return _phl_mr_process_by_mrc(phl_info, wifi_role, false, NULL, _phl_mr_dump_mac_addr);
}
u8 rtw_phl_mr_buddy_dump_mac_addr(void *phl,
					struct rtw_wifi_role_t *wifi_role)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;

	return _phl_mr_process_by_mrc(phl_info, wifi_role, true, NULL, _phl_mr_dump_mac_addr);
}

static inline u8
__phl_mr_process_ex(struct rtw_phl_com_t *phl_com,
		u8 role_map, void *data,
		u8(*ops_func)(void *drv_priv, u8 wr_idx, void *data))
{
	u8 ridx = 0;
	u8 ret = 0;
	struct rtw_wifi_role_t *wr = NULL;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (role_map & BIT(ridx)) {
			wr = &phl_com->wifi_roles[ridx];
			_os_warn_on(!wr->active);

			if (ops_func)
				if (true == ops_func(phl_com->drv_priv, wr->id, data))
					ret++;
		}
	}
	return ret;
}

u8 rtw_phl_mr_process_by_band(void *phl,
		enum phl_band_idx band_idx, void *data,
		u8(*ops_func)(void *drv_priv, u8 wr_idx, void *data))
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);

	return __phl_mr_process_ex(phl_info->phl_com, band_ctrl->role_map, data, ops_func);
}

bool rtw_phl_mr_query_info(void *phl,
                           struct rtw_wifi_role_t *wrole,
                           struct rtw_wifi_role_link_t *rlink,
                           struct mr_query_info *info)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);

	info->op_mode = band_ctrl->op_mode;
	info->op_type = band_ctrl->op_type;
	_os_mem_cpy(phl_to_drvpriv(phl_info), &info->cur_info,
			&band_ctrl->cur_info, sizeof(struct mr_info));
	return true;
}

void rtw_phl_mr_ops_init(void *phl, struct rtw_phl_mr_ops *mr_ops)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);

	mr_ctl->mr_ops.priv = mr_ops->priv;
#ifdef CONFIG_PHL_P2PPS
	mr_ctl->mr_ops.phl_mr_update_noa = mr_ops->phl_mr_update_noa;
#endif /* CONFIG_PHL_P2PPS */
#ifdef CONFIG_MCC_SUPPORT
	if (mr_ops->mcc_ops != NULL)
		rtw_phl_mcc_init_ops(phl_info, mr_ops->mcc_ops);
#endif
#ifdef CONFIG_DBCC_SUPPORT
	mr_ctl->mr_ops.dbcc_protocol_hdl = mr_ops->dbcc_protocol_hdl;
#endif

}

u8 rtw_phl_mr_get_opch_list(void *phl, u8 hw_band,
                            struct rtw_chan_def *chdef_list, u8 list_size,
                            struct rtw_wifi_role_link_t *rlink[], u8 rlink_num)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
	void *drv = phl_to_drvpriv(phl_info);
	struct rtw_chan_ctx *chanctx = NULL;
	int ctx_num = 0;
	u8 total_op_num = 0, i = 0;

	if((chdef_list == NULL) || (list_size == 0)){
		PHL_ERR("Parameter Invalid!\n");
		goto _exit;
	}

	ctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
	if (ctx_num == 0){
		PHL_DBG("ctx_num == 0!\n");
		goto _exit;
	}

	_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
	phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {

		if(total_op_num >= list_size)
			break;

		if (rlink_num != 0 && rlink != NULL) {
			for (i = 0; i < rlink_num; i++) {
				if (rlink[i]->hw_band == hw_band) {
					if (rlink[i]->chandef.chan == chanctx->chan_def.chan) {
						*(chdef_list + total_op_num) = chanctx->chan_def;
						total_op_num++;
						break;
					}
				}
			}
		} else {
			*(chdef_list + total_op_num) = chanctx->chan_def;
			total_op_num++;
		}
	}
	_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
_exit:
	return total_op_num;
}

enum mr_op_mode
rtw_phl_mr_get_opmode(void *phl,
                      struct rtw_wifi_role_t *wrole,
                      struct rtw_wifi_role_link_t *rlink)
{
	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);

	return band_ctrl->op_mode;
}

void
phl_mr_check_ecsa(struct phl_info_t *phl_info,
                  enum phl_band_idx hw_band
)
{
#ifdef CONFIG_PHL_ECSA
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
	u8 role_map = band_ctrl->role_map;
	struct rtw_wifi_role_t *wr = NULL, *ap_wr = NULL, *sta_wr = NULL;
	u8 ridx;
	enum band_type ap_band_type = BAND_ON_24G, sta_band_type = BAND_ON_24G;
	enum phl_ecsa_start_reason reason = ECSA_START_UNKNOWN;
	u32 delay_start_ms = 0;
#ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
	u32 extend_option = 0;
#endif
	bool ecsa_allow = false;
	struct rtw_phl_ecsa_param param = {0};
	void *d = phlcom_to_drvpriv(phl_com);
	struct rtw_wifi_role_link_t *rlink = NULL, *sta_rlink = NULL, *ap_rlink = NULL;

	if(band_ctrl->op_mode != MR_OP_MCC)
		return;
	if(band_ctrl->op_type != MR_OP_TYPE_STATION_AP)
		return;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (role_map & BIT(ridx)) {
			wr = &(phl_com->wifi_roles[ridx]);

			if (wr->rlink_num > 1)
				continue;

			rlink = phl_get_rlink_by_hw_band(wr, hw_band);

			switch (wr->type) {
			case PHL_RTYPE_STATION:
			case PHL_RTYPE_P2P_GC:
			case PHL_RTYPE_TDLS:
				if (rlink->mstate == MLME_LINKED){
					sta_band_type = rlink->chandef.band;
					sta_wr = wr;
					sta_rlink = rlink;
				}
				break;
			case PHL_RTYPE_AP:
			case PHL_RTYPE_VAP:
			case PHL_RTYPE_P2P_GO:
			case PHL_RTYPE_MESH:
				if (rlink->mstate == MLME_LINKED){
					ap_band_type = rlink->chandef.band;
					ap_wr = wr;
					ap_rlink = rlink;
				}
				break;
			case PHL_RTYPE_MONITOR:
			case PHL_RTYPE_P2P_DEVICE:
			default :
				break;
			}
		}
	}

	if (!sta_rlink || !ap_rlink)
		return;

	if(sta_band_type == BAND_ON_24G){
		if(ap_band_type == BAND_ON_24G)
			reason = ECSA_START_MCC_24G_TO_24G;
		else if(ap_band_type == BAND_ON_5G)
			reason = ECSA_START_MCC_5G_TO_24G;
		else
			reason = ECSA_START_UNKNOWN;
	}
	else if(sta_band_type == BAND_ON_5G){
		if(ap_band_type == BAND_ON_24G)
			reason = ECSA_START_MCC_24G_TO_5G;
		else if(ap_band_type == BAND_ON_5G)
			reason = ECSA_START_MCC_5G_TO_5G;
		else
			reason = ECSA_START_UNKNOWN;
	}
	else{
		reason = ECSA_START_UNKNOWN;
	}

	if(reason != ECSA_START_UNKNOWN){
		ecsa_allow = rtw_phl_ecsa_check_allow(phl_info,
		                                      ap_wr,
		                                      sta_rlink->chandef,
		                                      reason,
#ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
		                                      &extend_option,
#endif
		                                      &delay_start_ms);
	}

	if(ecsa_allow){
		param.ecsa_type = ECSA_TYPE_AP;
		param.count = ECSA_DEFAULT_CHANNEL_SWITCH_COUNT;
		param.delay_start_ms = delay_start_ms;
		param.flag = 0;
		param.mode = CHANNEL_SWITCH_MODE_NORMAL;
		param.ch = sta_rlink->chandef.chan;
		param.op_class = rtw_phl_get_operating_class(sta_rlink->chandef);
		_os_mem_cpy(d, &(param.new_chan_def), &(sta_rlink->chandef),
			    sizeof(struct rtw_chan_def));

#ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
		rtw_phl_ecsa_extend_option_hdlr(extend_option,
						ap_rlink,
						&param);
#endif

		pstatus = rtw_phl_ecsa_start(phl_info,
		                             ap_wr,
		                             ap_rlink,
		                             &param);
		if(pstatus == RTW_PHL_STATUS_SUCCESS)
			PHL_INFO("%s: ECSA start OK!\n", __FUNCTION__);
		else
			PHL_INFO("%s: ECSA start fail!\n", __FUNCTION__);
	}
#endif /* CONFIG_PHL_ECSA */
}

void
phl_mr_check_ecsa_cancel(struct phl_info_t *phl_info,
                         struct rtw_wifi_role_t *wrole,
                         struct rtw_wifi_role_link_t *rlink)
{
#ifdef CONFIG_PHL_ECSA
	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);

	if(band_ctrl->op_mode != MR_OP_MCC)
		return;
	if(band_ctrl->op_type != MR_OP_TYPE_STATION_AP)
		return;

	pstatus = rtw_phl_ecsa_cancel(phl_info, wrole);
	if(pstatus == RTW_PHL_STATUS_SUCCESS)
		PHL_INFO("%s: ECSA cancel OK!\n", __FUNCTION__);
	else
		PHL_INFO("%s: ECSA cancel fail!\n", __FUNCTION__);
#endif /* CONFIG_PHL_ECSA */
}

enum rtw_phl_status
phl_mr_err_recovery(struct phl_info_t *phl, enum phl_msg_evt_id eid)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;

	if (eid == MSG_EVT_SER_M5_READY) {
		/* SER L1 DONE event */
		rtw_phl_tdmra_recovery(phl, HW_BAND_0);
	}

	return status;
}
#ifdef CONFIG_DBCC_P2P_BG_LISTEN
struct rtw_wifi_role_link_t *
phl_mr_get_first_rlink_by_band_ex(struct phl_info_t *phl,
				enum phl_band_idx band,
				bool linked)
{
	struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, band);
	struct rtw_wifi_role_t *wrole = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 role_map = band_ctrl->role_map;
	u8 ridx = 0, idx = 0;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (!(role_map & BIT(ridx)))
			continue;
		wrole = &phl->phl_com->wifi_roles[ridx];

		for (idx = 0; idx < wrole->rlink_num; idx++) {
			rlink = get_rlink(wrole, idx);
			if (linked && rlink->chanctx == NULL)
				continue;
			if (rlink->hw_band == band) {
				PHL_INFO("%s: ridx(%d), rlink[%d]\n", __FUNCTION__,
					ridx, idx);
				return rlink;
			}
		}
	}
	return NULL;
}
#endif

struct rtw_wifi_role_link_t *
phl_mr_get_first_rlink_by_band(struct phl_info_t *phl,
				enum phl_band_idx band)
{
	struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, band);
	struct rtw_wifi_role_t *wrole = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	u8 role_map = band_ctrl->role_map;
	u8 ridx = 0, idx = 0;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (!(role_map & BIT(ridx)))
			continue;
		wrole = &phl->phl_com->wifi_roles[ridx];

		for (idx = 0; idx < wrole->rlink_num; idx++) {
			rlink = get_rlink(wrole, idx);
			if (rlink->chanctx == NULL)
				continue;
			if (rlink->hw_band == band) {
				PHL_INFO("%s: ridx(%d), rlink[%d]\n", __FUNCTION__,
					ridx, idx);
				return rlink;
			}
		}
	}
	return NULL;
}

struct rtw_wifi_role_link_t *
phl_mr_get_rlink_stay_in_cur_chdef(struct phl_info_t *phl,
				enum phl_band_idx band)
{
	struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, band);
	struct rtw_wifi_role_t *wrole = NULL;
	struct rtw_wifi_role_link_t *rlink = NULL;
	struct rtw_chan_def cur_chdef = {0};
	u8 role_map = band_ctrl->role_map;
	u8 ridx = 0, idx = 0;

	rtw_hal_get_cur_chdef(phl->hal, band, &cur_chdef);
	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (!(role_map & BIT(ridx)))
			continue;
		wrole = &phl->phl_com->wifi_roles[ridx];
		for (idx = 0; idx < wrole->rlink_num; idx++) {
			rlink = get_rlink(wrole, idx);
			if (rlink->chanctx == NULL)
				continue;
			if (rlink->hw_band != band)
				continue;
			if (rlink->chanctx->chan_def.chan == cur_chdef.chan) {
				PHL_INFO("%s: ridx(%d), rlink[%d]\n", __FUNCTION__,
					ridx, idx);
				return rlink;
			}
		}
	}
	return NULL;
}


/* MR coex related code */

