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

#ifdef CONFIG_MCC_SUPPORT
#include "phl_mcc.h"
void _mcc_dump_state(enum rtw_phl_mcc_state *state)
{
	if (MCC_NONE == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_NONE\n");
	} else if (MCC_CFG_EN_INFO == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_CFG_EN_INFO\n");
	} else if (MCC_TRIGGER_FW_EN == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_TRIGGER_FW_EN\n");
	} else if (MCC_FW_EN_FAIL == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_FW_EN_FAIL\n");
	} else if (MCC_RUNING == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_RUNING\n");
	} else if (MCC_TRIGGER_FW_DIS == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_TRIGGER_FW_DIS\n");
	} else if (MCC_FW_DIS_FAIL == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_FW_DIS_FAIL\n");
	} else if (MCC_STOP == *state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_state(): MCC_STOP\n");
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_dump_state(): Undefined state(%d)\n",
			*state);
	}
}

void _mcc_dump_mode(enum rtw_phl_tdmra_wmode *mode)
{
	if (RTW_PHL_TDMRA_AP_CLIENT_WMODE == *mode) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_mode(): RTW_PHL_TDMRA_AP_CLIENT_WMODE\n");
	} else if (RTW_PHL_TDMRA_2CLIENTS_WMODE == *mode) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_mode(): RTW_PHL_TDMRA_2CLIENTS_WMODE\n");
	} else if (RTW_PHL_TDMRA_AP_WMODE == *mode) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_mode(): RTW_PHL_TDMRA_AP_WMODE\n");
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_dump_mode(): Undefined mode(%d)\n",
			*mode);
	}
}

void _mcc_dump_sync_tsf_info(struct rtw_phl_mcc_sync_tsf_info *info)
{
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_sync_tsf_info(): sync_en(%d), source macid(%d), target macid(%d), offset(%d)\n",
		info->sync_en, info->source, info->target, info->offset);
}

void _mcc_dump_dur_info(struct rtw_phl_mcc_dur_info *dur_i)
{
	struct rtw_phl_mcc_dur_lim_info *dur_l = NULL;

	dur_l = &dur_i->dur_limit;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_dump_role_info(): dur(%d), dur lim info: enable(%d), tag(%d), max_dur(%d)\n",
		dur_i->dur, dur_l->enable, dur_l->tag, dur_l->max_dur);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< _mcc_dump_role_info(): max_toa(%d), max_tob(%d)\n",
		dur_l->max_toa, dur_l->max_tob);
}

void _mcc_dump_role_info(struct rtw_phl_mcc_role *mrole)
{
	struct rtw_phl_mcc_policy_info *policy = &mrole->policy;
	u8 i = 0;

	policy = &mrole->policy;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_dump_role_info(): wrole id(%d), type(%d), macid(%d), bcn_intvl(%d)\n",
		mrole->wrole->id, mrole->wrole->type, mrole->macid,
		mrole->bcn_intvl);
	for (i = 0; i < PHL_MACID_MAX_ARRAY_NUM; i++) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_role_info(): macid_map[%d]= 0x%08X\n",
			i, mrole->used_macid.bitmap[i]);
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_role_info(): chan(%d), center_ch(%d), bw(%d), offset(%d)\n",
		mrole->chandef->chan, mrole->chandef->center_ch,
		mrole->chandef->bw, mrole->chandef->offset);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_role_info(): group(%d), c2h_rpt(%d), tx_null_early(%d)\n",
		mrole->group, policy->c2h_rpt, policy->tx_null_early);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_role_info(): dis_tx_null(%d), in_curr_ch(%d), dis_sw_retry(%d)\n",
		policy->dis_tx_null, policy->in_curr_ch, policy->dis_sw_retry);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_role_info(): sw_retry_count(%d), rfk_chk(%d)\n",
		policy->sw_retry_count, policy->rfk_chk);
	_mcc_dump_dur_info(&policy->dur_info);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< _mcc_dump_role_info(): courtesy_en(%d), courtesy_num(%d), courtesy_target(0x%x)\n",
		policy->courtesy_en, policy->courtesy_num,
		policy->courtesy_target);
}

void _mcc_dump_pattern(struct rtw_phl_mcc_pattern *m_pattern)
{
	struct rtw_phl_mcc_courtesy *courtesy_i = &m_pattern->courtesy_i;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_dump_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d), bcns_offset(%d), calc_fail(%d), d_r_d_a_spacing_max(%d), c_en(%d)\n",
		m_pattern->tob_r, m_pattern->toa_r, m_pattern->tob_a,
		m_pattern->toa_a, m_pattern->bcns_offset, m_pattern->calc_fail,
		m_pattern->d_r_d_a_spacing_max, courtesy_i->c_en);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_pattern(): slot_num(%d), bt_slot_num(%d)\n",
		m_pattern->slot_num, m_pattern->bt_slot_num);
	if (courtesy_i->c_en) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< _mcc_dump_pattern(): c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
			courtesy_i->c_en, courtesy_i->c_num,
			courtesy_i->src_role->macid,
			courtesy_i->tgt_role->macid);
	}
}

void _mcc_dump_ref_role_info(struct rtw_phl_mcc_en_info *info)
{
	struct rtw_phl_mcc_role *ref_role = NULL;

	ref_role = get_ref_role(info);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_ref_role_info(): mrole idx(%d), wrole id(%d), macid(%d) chan(%d), bw(%d), offset(%d)\n",
		info->ref_role_idx, ref_role->wrole->id, ref_role->macid,
		ref_role->chandef->chan, ref_role->chandef->bw,
		ref_role->chandef->offset);
}

void _mcc_dump_en_info(struct rtw_phl_mcc_en_info *info)
{
	struct rtw_phl_mcc_role *m_role = NULL;
	u8 midx = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_en_info(): mrole_map(0x%x), role_num(%d), mcc_intvl(%d), Start tsf(0x%08X %08X)\n",
		info->mrole_map, info->mrole_num, info->mcc_intvl,
		info->tsf_high, info->tsf_low);
	_mcc_dump_ref_role_info(info);
	_mcc_dump_sync_tsf_info(&info->sync_tsf_info);
	_mcc_dump_pattern(&info->m_pattern);
	for (midx = 0; midx < MCC_ROLE_NUM; midx++) {
		if (!(info->mrole_map & BIT(midx)))
			continue;
		m_role = &info->mcc_role[midx];
		_mcc_dump_role_info(m_role);
	}
}

void _mcc_dump_bt_ino(struct rtw_phl_mcc_bt_info *bt_info)
{
	u8 seg_num = BT_SEG_NUM;

	if (bt_info->bt_seg_num > seg_num)
		return;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_dump_bt_ino(): bt_dur(%d), bt_seg_num(%d), bt_seg[0](%d), bt_seg[1](%d), add_bt_role(%d)\n",
		bt_info->bt_dur, bt_info->bt_seg_num, bt_info->bt_seg[0],
		bt_info->bt_seg[1], bt_info->add_bt_role);
}

void _mcc_dump_mcc_info(struct phl_mcc_info *minfo)
{
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_dump_mcc_info():\n");
	_mcc_dump_mode(&minfo->mcc_mode);
	_mcc_dump_state(&minfo->state);
	_mcc_dump_bt_ino(&minfo->bt_info);
	_mcc_dump_en_info(&minfo->en_info);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< _mcc_dump_mcc_info():\n");
}

void _mcc_set_state(struct phl_mcc_info *minfo, enum rtw_phl_mcc_state state)
{
	PHL_TRACE(COMP_PHL_MCC, _PHL_ALWAYS_, "_mcc_set_state(): Set from (%d) to (%d)\n",
		minfo->state, state);
	minfo->state = state;
	_mcc_dump_state(&minfo->state);
}

bool _mcc_is_ap_category(struct rtw_wifi_role_t *wrole)
{
	bool ret = false;

	if (wrole->type == PHL_RTYPE_AP || wrole->type == PHL_RTYPE_P2P_GO)
		ret = true;
	return ret;
}

bool _mcc_is_client_category(struct rtw_wifi_role_t *wrole)
{
	bool ret = false;

	if (wrole->type == PHL_RTYPE_STATION || wrole->type == PHL_RTYPE_P2P_GC || wrole->type == PHL_RTYPE_TDLS)
		ret = true;
	return ret;
}

struct rtw_phl_mcc_role *
_mcc_get_mrole_by_wrole(struct phl_mcc_info *minfo,
				struct rtw_wifi_role_t *wrole)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *m_role = NULL;
	u8 midx = 0;

	for (midx = 0; midx < MCC_ROLE_NUM; midx++) {
		if (!(en_info->mrole_map & BIT(midx)))
			continue;
		m_role = &en_info->mcc_role[midx];
		if (m_role->wrole == wrole) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_get_mrole_by_wrole(): Get mrole in mrole_idx(%d), wrole->type(%d), wrole->id(%d)\n",
				midx, wrole->type, wrole->id);
			return m_role;
		}
	}
	return NULL;
}

u8
_mcc_get_mrole_idx_by_wrole(struct phl_mcc_info *minfo,
				struct rtw_wifi_role_t *wrole, u8 *idx)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *m_role = NULL;
	u8 midx = 0;

	for (midx = 0; midx < MCC_ROLE_NUM; midx++) {
		if (!(en_info->mrole_map & BIT(midx)))
			continue;
		m_role = &en_info->mcc_role[midx];
		if (m_role->wrole == wrole) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_get_mrole_idx_by_wrole(): Get mrole in mrole_idx(%d)\n",
				midx);
			*idx = midx;
			status = RTW_PHL_STATUS_SUCCESS;
			break;
		}
	}
	return status;
}

struct rtw_phl_mcc_role *
_mcc_get_mrole_by_category(struct rtw_phl_mcc_en_info *en_info,
			enum _mcc_role_cat category)
{
	struct rtw_phl_mcc_role *m_role = NULL;
	u8 midx = 0;

	for (midx = 0; midx < MCC_ROLE_NUM; midx++) {
		if (!(en_info->mrole_map & BIT(midx)))
			continue;
		m_role = &en_info->mcc_role[midx];
		if (MCC_ROLE_AP_CAT == category) {
			if (_mcc_is_ap_category(m_role->wrole))
				return m_role;
		} else if (MCC_ROLE_CLIENT_CAT == category) {
			if (_mcc_is_client_category(m_role->wrole))
				return m_role;
		} else {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_get_mrole_by_category(): Undefined category(%d)\n",
				category);
			break;
		}
	}
	return NULL;
}

enum rtw_phl_status _mcc_transfer_mode(struct phl_info_t *phl,
				struct phl_mcc_info *minfo, u8 role_map)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_wifi_role_t *wrole = NULL;
	u8 ridx = 0, ap_num = 0, client_num = 0;

	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (!(role_map & BIT(ridx)))
			continue;
		wrole = phl_get_wrole_by_ridx(phl, ridx);
		if (wrole == NULL) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_transfer_mode(): get wrole fail, role_idx(%d)\n",
				ridx);
			goto exit;
		}
		if (_mcc_is_client_category(wrole)) {
			client_num++;
		} else if (_mcc_is_ap_category(wrole)) {
			ap_num++;
		} else {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_transfer_mode(): undefined category, role->type(%d), ridx(%d), shall check code flow\n",
				wrole->type, ridx);
			goto exit;
		}
	}
	if ((client_num + ap_num > MAX_MCC_GROUP_ROLE)){
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_transfer_mode(): client_num(%d) + ap_num(%d) is illegal num, please check code flow\n",
			client_num, ap_num);
		goto exit;
	}
	if (ap_num == 1 && client_num == 1) {
		minfo->mcc_mode = RTW_PHL_TDMRA_AP_CLIENT_WMODE;
	} else if (ap_num == 0 && client_num == 2) {
		minfo->mcc_mode = RTW_PHL_TDMRA_2CLIENTS_WMODE;
	} else if (ap_num == 1 && client_num == 0) {
		minfo->mcc_mode = RTW_PHL_TDMRA_AP_WMODE;
	} else {
		minfo->mcc_mode = RTW_PHL_TDMRA_UNKNOWN_WMODE;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_transfer_mode(): Undefined mode, please check code flow\n");
		goto exit;
	}
	_mcc_dump_mode(&minfo->mcc_mode);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

enum rtw_phl_status _mcc_get_role_map(struct phl_info_t *phl,
				struct hw_band_ctl_t *band_ctrl, u8 *role_map)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	void *drv = phl_to_drvpriv(phl);
	struct rtw_chan_ctx *chanctx = NULL;
	_os_list *chan_ctx_list = &band_ctrl->chan_ctx_queue.queue;

	*role_map = 0;
	_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _ps, NULL);
	phl_list_for_loop(chanctx, struct rtw_chan_ctx, chan_ctx_list, list) {
		*role_map |= chanctx->role_map;
	}
	_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _ps, NULL);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_get_role_map(): role_map(%d)\n",
		*role_map);
	status = RTW_PHL_STATUS_SUCCESS;
	return status;
}

void _mcc_set_fw_log_info(struct phl_info_t *phl, u8 hw_band,
			bool en_fw_mcc_log, u8 fw_mcc_log_lv)
{
	struct phl_mcc_info *minfo = get_mcc_info(phl, hw_band);

	if (minfo->fw_log_i.en_fw_mcc_log != en_fw_mcc_log) {
		minfo->fw_log_i.en_fw_mcc_log = en_fw_mcc_log;
		minfo->fw_log_i.update = true;
	}
	if (minfo->fw_log_i.fw_mcc_log_lv != fw_mcc_log_lv) {
		minfo->fw_log_i.fw_mcc_log_lv = fw_mcc_log_lv;
		minfo->fw_log_i.update = true;
	}
}

void _mcc_up_fw_log_setting(struct phl_info_t *phl, struct phl_mcc_info *minfo)
{
	struct phl_mcc_fw_log_info *fw_log_i = &minfo->fw_log_i;

	if (fw_log_i->update) {
		rtw_hal_cfg_fw_mcc_log(phl->hal, fw_log_i->en_fw_mcc_log);
		fw_log_i->update = false;
	}
}

void _mcc_set_unspecific_dur(struct phl_mcc_info *minfo)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *m_role = NULL;
	u8 midx = 0;

	for (midx = 0; midx < MCC_ROLE_NUM; midx++) {
		if (!(en_info->mrole_map & BIT(midx)))
			continue;
		m_role = &en_info->mcc_role[midx];
		m_role->policy.dur_info.dur = MCC_DUR_NONSPECIFIC;
	}
}

void _mcc_fill_dur_lim_info(struct phl_info_t *phl,
				struct rtw_phl_mcc_role *mrole,
				struct phl_mcc_dur_lim_req_info *dur_req)
{
	struct rtw_phl_mcc_dur_info *dur_i = &mrole->policy.dur_info;
	struct rtw_phl_mcc_dur_lim_info *dur_lim = &dur_i->dur_limit;
	u64 tsf_lim = 0;
	u32 max_toa = 0, max_tob = 0, max_dur = 0;
	u32 bcn_intvl = mrole->bcn_intvl * TU;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_dur_lim_info(): dur_req: tag(%d), enable(%d), start_t_h(0x%08x), start_t_l(0x%08x), dur(%d), intvl(%d)\n",
		dur_req->tag, dur_req->enable, dur_req->start_t_h,
		dur_req->start_t_l, dur_req->dur, dur_req->intvl);
	dur_lim->enable = false;
	if (!dur_req->enable) {
		goto exit;
	}
	if (bcn_intvl != dur_req->intvl) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_dur_lim_info(): not support bcn_intvl(%d) != dur_req.intvl(%d), please check code\n",
			bcn_intvl, dur_req->intvl);
		goto exit;
	}
	/*Assume bcn allocat in TSF % BcnInvtal = 0*/
	tsf_lim = dur_req->start_t_h;
	tsf_lim = tsf_lim << 32;
	tsf_lim |= dur_req->start_t_l;
	max_toa = (u16)_os_modular64(tsf_lim, mrole->bcn_intvl * TU);
	if (max_toa >= (mrole->bcn_intvl * TU - dur_req->dur) ||
		max_toa == 0) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_dur_lim_info(): not support bcn allocate in limited slot, please check code\n");
		goto exit;
	}
	max_dur = dur_req->intvl - dur_req->dur;
	max_toa = max_toa / TU;
	max_dur = max_dur / TU;
	max_tob = max_dur - max_toa;

	dur_lim->max_toa = (u16)max_toa;
	dur_lim->max_tob = (u16)max_tob;
	dur_lim->max_dur = (u16)max_dur;
	dur_lim->tag = dur_req->tag;
	dur_lim->enable = true;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_dur_lim_info(): dur_lim_info: enable(%d), tag(%d), max_toa(%d), max_tob(%d), max_dur(%d)\n",
			dur_lim->enable, dur_lim->tag, dur_lim->max_toa,
			dur_lim->max_tob, dur_lim->max_dur);
	return;
}

void _mcc_fill_default_policy(struct phl_info_t *phl,
				struct rtw_phl_mcc_role *mrole)
{
	struct rtw_phl_mcc_policy_info *policy = &mrole->policy;
	struct phl_mcc_dur_lim_req_info dur_req = {0};

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_default_policy(): set mcc policy by default setting\n");
	policy->c2h_rpt = RTW_MCC_RPT_ALL;
	policy->tx_null_early = 3;
	policy->dis_tx_null = _mcc_is_client_category(mrole->wrole) ? 0 : 1;
	policy->in_curr_ch = 0;
	policy->dis_sw_retry = 1;
	policy->sw_retry_count = 0;
	policy->dur_info.dur = _mcc_is_client_category(mrole->wrole) ?
					DEFAULT_CLIENT_DUR : DEFAULT_AP_DUR;
	phl_mr_mcc_query_role_time_slot_lim(phl, mrole->wrole, &dur_req);
	_mcc_fill_dur_lim_info(phl, mrole, &dur_req);
	policy->rfk_chk = rtw_hal_check_ch_rfk(phl->hal, &mrole->wrole->chandef);
	if (false == policy->rfk_chk) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_default_policy(): No rfk, it will degrade perormance, please check code\n");
	}
}

void _mcc_fill_mcc_role_policy_info(struct phl_info_t *phl,
		struct rtw_wifi_role_t *wrole, struct rtw_phl_mcc_role *mrole)
{
	struct phl_com_mcc_info *com_info = phl_to_com_mcc_info(phl);
	struct rtw_phl_mcc_policy_info *policy = &mrole->policy;
	struct rtw_phl_mcc_setting_info param = {0};
	struct phl_mcc_info *minfo = get_mcc_info(phl, wrole->hw_band);

	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, ">>> _mcc_fill_mcc_role_policy_info()\n");
	_mcc_fill_default_policy(phl, mrole);
	if (NULL == com_info->ops.mcc_get_setting)
		goto exit;
	param.wrole = wrole;
	param.role_map = minfo->role_map;
	param.tx_null_early = NONSPECIFIC_SETTING;
	param.dur = NONSPECIFIC_SETTING;
	if (!com_info->ops.mcc_get_setting(com_info->ops.priv, &param)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_mcc_role_policy_info(): mcc_get_setting from core layer fail\n");
		goto exit;
	}
	if (NONSPECIFIC_SETTING != param.tx_null_early) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_mcc_role_policy_info(): Core layer change tx_null_early from %d to %d\n",
			policy->tx_null_early, param.tx_null_early);
		policy->tx_null_early = param.tx_null_early;
	}
	if (NONSPECIFIC_SETTING != param.dur) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_mcc_role_policy_info(): Core layer change dur from %d to %d\n",
			policy->dur_info.dur, param.dur);
		policy->dur_info.dur = param.dur;
	}
	_mcc_set_fw_log_info(phl, wrole->hw_band, param.en_fw_mcc_log,
				param.fw_mcc_log_lv);
exit:
	return;
}

void _mcc_fill_macid_bitmap_by_role(struct phl_info_t *phl,
					struct rtw_phl_mcc_role *mrole)
{
	struct macid_ctl_t *mc = phl_to_mac_ctrl(phl);
	struct rtw_phl_mcc_macid_bitmap *used_macid = &mrole->used_macid;
	u8 i = 0, max_map_idx = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_fill_macid_bitmap_by_role()\n");
	for (i = 0; i < PHL_MACID_MAX_ARRAY_NUM; i++) {
		if ((mc->wifi_role_usedmap[mrole->wrole->id][i] != 0) &&
							(max_map_idx <= i)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_macid_bitmap_by_role(): macid_map[%d]=0x%08x\n",
				i, mc->wifi_role_usedmap[mrole->wrole->id][i]);
			max_map_idx = i;
		}
	}
	used_macid->bitmap = &mc->wifi_role_usedmap[mrole->wrole->id][0];
	used_macid->len = (max_map_idx + 1) * sizeof(u32);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_macid_bitmap_by_role(): bitmap->len(%d), max_map_idx(%d)\n",
		used_macid->len, max_map_idx);
}

enum rtw_phl_status _mcc_fill_mcc_role_basic_info(struct phl_info_t *phl,
		struct rtw_wifi_role_t *wrole, struct rtw_phl_mcc_role *mrole)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_stainfo_t *sta = rtw_phl_get_stainfo_self(phl, wrole);

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_fill_mcc_role_basic_info()\n");
	if (sta == NULL) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_mcc_role_basic_info(): transfer mcc mode failed\n");
		goto exit;
	}
	mrole->wrole = wrole;
	mrole->macid = sta->macid;
#ifdef RTW_PHL_BCN
	if (_mcc_is_ap_category(wrole))
		mrole->bcn_intvl = (u16)wrole->bcn_cmn.bcn_interval;
	else
#endif
		mrole->bcn_intvl = sta->asoc_cap.bcn_interval;
	if (mrole->bcn_intvl == 0) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_mcc_role_basic_info(): mrole->bcn_intvl ==0, please check code of core layer.\n");
		goto exit;
	}
	mrole->chandef = &wrole->chandef;
	_mcc_fill_macid_bitmap_by_role(phl, mrole);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

enum rtw_phl_status _mcc_fill_ref_role_info(struct phl_info_t *phl,
			struct rtw_phl_mcc_en_info *en_info,
			struct rtw_wifi_role_t *wrole)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_mcc_role *mrole = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_fill_ref_role_info()\n");
	mrole = &en_info->mcc_role[REF_ROLE_IDX];
	status = _mcc_fill_mcc_role_basic_info(phl, wrole, mrole);
	if (RTW_PHL_STATUS_SUCCESS != status) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_ref_role_info(): set basic info failed\n");
		goto exit;
	}
	_mcc_fill_mcc_role_policy_info(phl, wrole, mrole);
	en_info->mrole_map |= BIT(REF_ROLE_IDX);
	en_info->mrole_num++;
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_ref_role_info(): status(%d), wrole id(%d), wrole->type(%d), Fill mrole(%d) Info\n",
			status, wrole->id, wrole->type, REF_ROLE_IDX);
	return status;
}

enum rtw_phl_status _mcc_fill_role_info(struct phl_info_t *phl,
			struct rtw_phl_mcc_en_info *en_info, u8 role_map,
			struct rtw_wifi_role_t *cur_role)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_wifi_role_t *wrole = NULL;
	struct rtw_phl_mcc_role *mrole = NULL;
	u8 ridx = 0, mcc_idx = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_fill_role_info()\n");
	if (RTW_PHL_STATUS_SUCCESS != _mcc_fill_ref_role_info(phl, en_info,
								cur_role)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_info(): set ref role info failed\n");
		goto exit;
	}
	mcc_idx = en_info->mrole_num;
	role_map &= ~(BIT(cur_role->id));
	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
		if (!(role_map & BIT(ridx)))
			continue;
		wrole = phl_get_wrole_by_ridx(phl, ridx);
		if (wrole == NULL) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_info(): get wrole fail, role_idx(%d)\n",
				ridx);
			goto exit;
		}
		if (mcc_idx >= MCC_ROLE_NUM) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_info(): mcc_idx(%d) >= MCC_ROLE_NUM(%d)\n",
				mcc_idx, MCC_ROLE_NUM);
			goto exit;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_role_info(): wrole(%d), wrole->type(%d), Fill mrole(%d) Info\n",
			ridx, wrole->type, mcc_idx);
		mrole = &en_info->mcc_role[mcc_idx];
		status = _mcc_fill_mcc_role_basic_info(phl, wrole, mrole);
		if (RTW_PHL_STATUS_SUCCESS != status) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_info(): set basic info failed\n");
			goto exit;
		}
		_mcc_fill_mcc_role_policy_info(phl, wrole, mrole);
		en_info->mrole_map |= BIT(mcc_idx);
		en_info->mrole_num++;
		mcc_idx ++;
	}
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< _mcc_fill_role_info(): status(%d), role_map(0x%x), mcc_role_map(0x%x)\n",
		status, role_map, en_info->mrole_map);
	return status;
}

void _mcc_fill_coex_mode(struct phl_info_t *phl, struct phl_mcc_info *minfo)
{
	/* if get from core or ....
	else*/
	minfo->coex_mode = RTW_PHL_MCC_COEX_MODE_BT_MASTER;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_coex_mode(): Set default mode(%d)\n",
		minfo->coex_mode);
}

void _mcc_fill_bt_dur(struct phl_info_t *phl, struct phl_mcc_info *minfo)
{
	minfo->bt_info.bt_dur = (u16)rtw_hal_get_btc_req_slot(phl->hal);
	minfo->bt_info.bt_seg_num = 1;
	minfo->bt_info.bt_seg[0] = minfo->bt_info.bt_dur;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_bt_dur(): minfo->bt_info.bt_dur(%d)\n",
		minfo->bt_info.bt_dur);

}

/*
 * fill slot info
 * @m_pattern: pattern info
 * @bt_role: True: BT Role; False: Wifi Role
 * @dur: time slot
 * @mrole: mcc role info
 */
void _mcc_fill_slot_info(struct rtw_phl_mcc_pattern *m_pattern, bool bt_role,
				u16 dur, struct rtw_phl_mcc_role *mrole)
{
	if (m_pattern->slot_num >= SLOT_NUM) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_slot_info(): Fail, m_pattern->slot_num(%d) >= SLOT_NUM(%d)\n",
		m_pattern->slot_num, SLOT_NUM);
		return;
	}
	if (bt_role) {
		m_pattern->slot_order[m_pattern->slot_num].bt_role = true;
		m_pattern->slot_order[m_pattern->slot_num].slot = dur;
		m_pattern->slot_order[m_pattern->slot_num].mrole = NULL;
		m_pattern->bt_slot_num++;
	} else {
		m_pattern->slot_order[m_pattern->slot_num].bt_role = false;
		m_pattern->slot_order[m_pattern->slot_num].slot = dur;
		m_pattern->slot_order[m_pattern->slot_num].mrole = mrole;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "m_pattern->slot_num(): Fill slot, Idx(%d), dur(%d), is BT slot(%d)\n",
		m_pattern->slot_num, dur, bt_role);
	m_pattern->slot_num++;
}

void _mcc_reset_minfo(struct phl_info_t *phl, struct phl_mcc_info *minfo,
				enum _mcc_minfo_reset_type reset_type)
{
	void *priv = phl_to_drvpriv(phl);

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_reset_minfo\n");
	if (reset_type == MINFO_RESET_ALL) {
		_os_mem_set(priv, minfo, 0, sizeof(struct phl_mcc_info));
		return;
	}
	if (reset_type & MINFO_RESET_EN_INFO)
		_os_mem_set(priv, &minfo->en_info, 0,
				sizeof(struct rtw_phl_mcc_en_info));
	if (reset_type & MINFO_RESET_MODE)
		_os_mem_set(priv, &minfo->mcc_mode, 0,
				sizeof(enum rtw_phl_tdmra_wmode));
	if (reset_type & MINFO_RESET_ROLE_MAP)
		_os_mem_set(priv, &minfo->role_map, 0,
				sizeof(minfo->role_map));
	if (reset_type & MINFO_RESET_STATE)
		_os_mem_set(priv, &minfo->state, 0,
				sizeof(enum rtw_phl_mcc_state));
	if (reset_type & MINFO_RESET_COEX_MODE)
		_os_mem_set(priv, &minfo->coex_mode, 0,
				sizeof(enum rtw_phl_mcc_coex_mode));
	if (reset_type & MINFO_RESET_BT_INFO)
		_os_mem_set(priv, &minfo->bt_info, 0,
				sizeof(struct rtw_phl_mcc_bt_info));
	if (reset_type & MINFO_RESET_PATTERN_INFO)
		_os_mem_set(priv, &minfo->en_info.m_pattern, 0,
				sizeof(struct rtw_phl_mcc_pattern));
}

void _mcc_clean_noa(struct phl_info_t *phl, struct rtw_phl_mcc_en_info *en_info)
{
	struct phl_com_mcc_info *com_info = phl_to_com_mcc_info(phl);
	struct rtw_phl_mcc_noa param = {0};

	if (com_info == NULL) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_clean_noa(): Get mcc common info failed\n");
	} else if (com_info->ops.mcc_update_noa) {
		struct rtw_phl_mcc_role *ap_role = NULL;
		ap_role = _mcc_get_mrole_by_category(en_info, MCC_ROLE_AP_CAT);
		if (NULL == ap_role) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_clean_noa(): Get AP role fail\n");
			goto exit;
		}
		param.wrole = ap_role->wrole;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_clean_noa()\n");
		com_info->ops.mcc_update_noa(com_info->ops.priv, &param);
	}
exit:
	return;
}

bool _tdmra_calc_noa_2wrole(struct phl_info_t *phl, struct phl_mcc_info *minfo,
				struct rtw_phl_mcc_noa *param)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_bt_info *bt = &minfo->bt_info;
	struct rtw_phl_mcc_role *role_ref = get_ref_role(en_info);
	struct rtw_phl_mcc_role *role_ano = (role_ref == &en_info->mcc_role[0])
				? &en_info->mcc_role[1] : &en_info->mcc_role[0];
	u16 d_r = role_ref->policy.dur_info.dur;
	u16 d_a = role_ano->policy.dur_info.dur;
	u64 mcc_start = 0, noa_start = 0;
	bool ret = false;

	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, ">>> _tdmra_calc_noa_2wrole()\n");
	mcc_start = en_info->tsf_high;
	mcc_start = mcc_start << 32;
	mcc_start |= en_info->tsf_low;
	if (_mcc_is_ap_category(role_ref->wrole)){
		/*calculate end time of GO*/
		noa_start = mcc_start + (d_r * TU);
		param->dur = en_info->mcc_intvl - d_r;
		param->wrole = role_ref->wrole;
	} else {
		u32 tsf_ref_h = 0, tsf_ref_l = 0, tsf_ano_h = 0, tsf_ano_l = 0;
		u64 tsf_ref = 0, tsf_ano = 0;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_tdmra_calc_noa_2wrole(): AP Role isn't ref role, we need to get 2 port tsf\n");
		_mcc_dump_bt_ino(bt);
		if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_get_2ports_tsf(
				phl->hal, role_ref->group, role_ref->macid,
				role_ano->macid, &tsf_ref_h, &tsf_ref_l,
				&tsf_ano_h, &tsf_ano_l)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_tdmra_calc_noa_2wrole(): Get 2 port tsf failed\n");
			goto exit;
		}
		tsf_ref = tsf_ref_h;
		tsf_ref = tsf_ref << 32;
		tsf_ref |= tsf_ref_l;
		tsf_ano = tsf_ano_h;
		tsf_ano = tsf_ano << 32;
		tsf_ano |= tsf_ano_l;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_tdmra_calc_noa_2wrole(): tsf_ref: 0x%08X %08x, tsf_ano: 0x%08x %08x\n",
			(u32)(tsf_ref >> 32), (u32)tsf_ref,
			(u32)(tsf_ano >> 32), (u32)tsf_ano);
		/*calculate end time of GO*/
		noa_start = mcc_start + (en_info->mcc_intvl * TU);
		if (bt->add_bt_role) {
			if(bt->bt_seg_num == 1) {
				noa_start -= (bt->bt_seg[0] * TU);
			} else if (bt->bt_seg_num == 2) {
				noa_start -= (bt->bt_seg[1] * TU);
			} else {
				PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_tdmra_calc_noa_2wrole(): error bt_seg_num(%d), please check code flow\n",
					bt->bt_seg_num);
				goto exit;
			}
		}
		noa_start = noa_start - tsf_ref + tsf_ano;
		param->dur = en_info->mcc_intvl - d_a;
		param->wrole = role_ano->wrole;
	}
	param->start_t_h = noa_start >> 32;
	param->start_t_l = (u32)noa_start;
	param->cnt = 255;
	param->interval = en_info->mcc_intvl;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_tdmra_calc_noa_2wrole(): IsGORef(%d), mcc_start(0x%08x %08x)\n",
		_mcc_is_ap_category(role_ref->wrole),
		(u32)(mcc_start >> 32), (u32)mcc_start);
	ret = true;
exit:
	return ret;
}

bool _tdmra_calc_noa_1wrole(struct phl_info_t *phl, struct phl_mcc_info *minfo,
				struct rtw_phl_mcc_noa *param)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *role_ref = get_ref_role(en_info);
	u16 d_r = role_ref->policy.dur_info.dur;
	u64 mcc_start = 0, noa_start = 0;
	bool ret = false;

	mcc_start = en_info->tsf_high;
	mcc_start = mcc_start << 32;
	mcc_start |= en_info->tsf_low;
	/*calculate end time of GO*/
	noa_start = mcc_start + (d_r * TU);
	param->dur = en_info->mcc_intvl - d_r;
	param->wrole = role_ref->wrole;
	param->start_t_h = noa_start >> 32;
	param->start_t_l = (u32)noa_start;
	param->cnt = 255;
	param->interval = en_info->mcc_intvl;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_tdmra_calc_noa_1wrole(): IsGORef(%d), mcc_start(0x%08x %08x)\n",
		_mcc_is_ap_category(role_ref->wrole),
		(u32)(mcc_start >> 32), (u32)mcc_start);
	ret = true;
	return ret;
}


void _mcc_up_noa(struct phl_info_t *phl, struct phl_mcc_info *minfo)

{
	struct phl_com_mcc_info *com_info = phl_to_com_mcc_info(phl);
	struct rtw_phl_mcc_noa param = {0};

	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, ">>> _mcc_up_noa()\n");
	if (com_info == NULL) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_up_noa(): Get mcc common info failed\n");
		goto exit;
	}
	if (!com_info->ops.mcc_update_noa)
		goto exit;
	if (RTW_PHL_TDMRA_AP_CLIENT_WMODE == minfo->mcc_mode) {
		if (false == _tdmra_calc_noa_2wrole(phl, minfo, &param))
			goto exit;
	} else if (RTW_PHL_TDMRA_AP_WMODE == minfo->mcc_mode) {
		if (false == _tdmra_calc_noa_1wrole(phl, minfo, &param))
			goto exit;
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_up_noa(): error wmode\n");
		_mcc_dump_mode(&minfo->mcc_mode);
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_up_noa(): NOA_start(0x%08x %08x), dur(%d), cnt(%d), interval(%d)\n",
		param.start_t_h, param.start_t_l, param.dur, param.cnt,
		param.interval);
	com_info->ops.mcc_update_noa(com_info->ops.priv, &param);
exit:
	return;
}

bool _mcc_adjust_dur_for_2g_mcc_2role_bt(struct phl_mcc_info *minfo)
{
	struct rtw_phl_mcc_bt_info *bt_info = &minfo->bt_info;
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *m_role1 = &en_info->mcc_role[0];
	struct rtw_phl_mcc_role *m_role2 = &en_info->mcc_role[1];
	u16 d1 = m_role1->policy.dur_info.dur;
	u16 d2 = m_role2->policy.dur_info.dur;
	u16 d1_max = (m_role1->policy.dur_info.dur_limit.enable) ?
		m_role1->policy.dur_info.dur_limit.max_dur : en_info->mcc_intvl;
	u16 d2_max = (m_role2->policy.dur_info.dur_limit.enable) ?
		m_role2->policy.dur_info.dur_limit.max_dur : en_info->mcc_intvl;
	u16 d1_min = _mcc_is_ap_category(m_role1->wrole) ?
					MIN_AP_DUR : MIN_CLIENT_DUR;
	u16 d2_min = _mcc_is_ap_category(m_role2->wrole) ?
					MIN_AP_DUR : MIN_CLIENT_DUR;
	u16 wifi_dur = 0, bt_dur = bt_info->bt_dur;
	u16 i = 0;
	bool adjust_ok = false;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_adjust_dur_for_2g_mcc_2role_bt(): mcc_intvl(%d), bt_dur(%d), d1(%d), d2(%d), d1_min(%d), d1_max(%d), d2_min(%d), d2_max(%d)\n",
		en_info->mcc_intvl, bt_dur, d1, d2, d1_min, d1_max, d2_min, d2_max);
	for (i = 0; i < en_info->mcc_intvl; i++) {
		wifi_dur = en_info->mcc_intvl - bt_dur;
		d1 = ((d1 * 100 / (d1 + d2)) * wifi_dur) / 100;
		if (d1 < d1_min) {
			d1 = d1_min;
		} else if (d1 > d1_max) {
			d1 = d1_max;
		}
		d2 = wifi_dur - d1;
		if (d2 < d2_min) {
			d2 = d2_min;
			d1 = wifi_dur - d2;
		} else if (d2 > d2_max) {
			d2 = d2_max;
			d1 = wifi_dur - d2;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_adjust_dur_for_2g_mcc_2role_bt(): Loop bt_dur(%d), d1(%d), d2(%d)\n",
				bt_dur, d1, d2);
		if ((d1 >= d1_min) && (d1 <= d1_max) &&
			(d2 >= d2_min) && (d2 <= d2_max)) {
			m_role1->policy.dur_info.dur = d1;
			m_role2->policy.dur_info.dur = d2;
			bt_info->bt_dur = bt_dur;
			en_info->m_pattern.d_r_d_a_spacing_max = bt_info->bt_dur;
			adjust_ok = true;
			break;
		}
		bt_dur--;
	}
	if (adjust_ok == false){
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_adjust_dur_for_2g_mcc_2role_bt(): Adjust fail\n");
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_adjust_dur_for_2g_mcc_2role_bt(): Adjust ok, d1(%d), d2(%d), bt dur(%d), d_r_d_a_spacing_max(%d)\n",
			m_role1->policy.dur_info.dur,
			m_role2->policy.dur_info.dur,
			bt_info->bt_dur, en_info->m_pattern.d_r_d_a_spacing_max);
	}
	return adjust_ok;
}

void _mcc_adjust_dur_for_2_band_mcc_2role_bt(struct phl_mcc_info *minfo,
	struct rtw_phl_mcc_role *role_2g, struct rtw_phl_mcc_role *role_non_2g)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	enum rtw_phl_mcc_coex_mode *coex_mode = &minfo->coex_mode;
	struct rtw_phl_mcc_policy_info *plcy_2g = &role_2g->policy;
	struct rtw_phl_mcc_policy_info *plcy_non2g = &role_non_2g->policy;
	u16 *bt_dur = &minfo->bt_info.bt_dur;
	u16 dur_2g = 0, dur_non2g = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): coex_mode(%d) 2G_Dur(%d), 5G_Dur(%d), BT_Dur(%d)\n",
		*coex_mode, plcy_2g->dur_info.dur, plcy_non2g->dur_info.dur,
		*bt_dur);
	if (plcy_non2g->dur_info.dur >= *bt_dur) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): 5G_Dur(%d) >= BT_Dur(%d), no need to adjust 5G duration for BT\n",
			plcy_non2g->dur_info.dur, *bt_dur);
		goto exit;
	}
	if (plcy_non2g->dur_info.dur_limit.enable &&
		plcy_non2g->dur_info.dur_limit.max_dur < *bt_dur) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): dur_limit.max_dur(%d) < bt_dur(%d), We can't adjust 5G duration(%d) for BT\n",
			plcy_non2g->dur_info.dur_limit.max_dur,
			*bt_dur, plcy_non2g->dur_info.dur);
		goto exit;
	}
	if (*coex_mode == RTW_PHL_MCC_COEX_MODE_BT_MASTER) {
		dur_non2g = *bt_dur;
		dur_2g = en_info->mcc_intvl - dur_non2g;
		if (plcy_2g->dur_info.dur_limit.enable &&
			plcy_2g->dur_info.dur_limit.max_dur < dur_2g) {
			dur_2g = plcy_2g->dur_info.dur_limit.max_dur;
			dur_non2g = en_info->mcc_intvl - dur_2g;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): plcy_2g->max_dur(%d) < dur_2g(%d), We can adjust some 5G duration for BT\n",
				plcy_2g->dur_info.dur_limit.max_dur, dur_2g);
		}
		plcy_non2g->dur_info.dur = dur_non2g;
		plcy_2g->dur_info.dur = dur_2g;
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): coex_mode == RTW_PHL_MCC_COEX_MODE_BT_MASTER, we adjust 5G duration for BT\n");
	} else if (*coex_mode == RTW_PHL_MCC_COEX_MODE_WIFI_MASTER) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): coex_mode == RTW_PHL_MCC_COEX_MODE_WIFI_MASTER, we don't adjust 5G duration for BT\n");
		goto exit;
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): coex_mode(%d), Undefined mode, ignore bt duration\n",
			*coex_mode);
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_adjust_dur_for_2_band_mcc_2role_bt(): After adjust, 2G_Dur(%d), 5G_Dur(%d), BT_Dur(%d)\n",
		plcy_2g->dur_info.dur, plcy_non2g->dur_info.dur,
		*bt_dur);
exit:
	return;
}

bool _mcc_need_to_seg_bt_dur(struct phl_mcc_info *minfo)
{
/* Not ready for implementation*/
	return false;
#if 0
	bool seg = false;
	struct rtw_phl_mcc_en_info *info = &minfo->en_info;
	struct rtw_phl_mcc_dur_lim_info *limit_i = NULL;
	u8 i = 0;

	if (minfo->mcc_mode != RTW_PHL_TDMRA_2CLIENTS_WMODE)
		goto exit;
	if (minfo->bt_info.bt_dur < BT_DUR_SEG_TH || BT_SEG_NUM < 2)
		goto exit;
	for (i = 0; i < MCC_ROLE_NUM; i++) {
		limit_i = &minfo->en_info.mcc_role[i].policy.dur_info.dur_limit;
		if (limit_i->enable) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_need_to_seg_bt_dur(): Can't seg bt slot when wifi slot with limitation\n");
			goto exit;
		}
	}
	seg = true;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_need_to_seg_bt_dur(): seg(%d)\n",
		seg);
	return seg;
#endif
}

/*
 * 2 wifi slot req + bt slot req
 */
void _mcc_discision_dur_for_2g_mcc_2role_bt(struct phl_mcc_info *minfo)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *m_role1 = &en_info->mcc_role[0];
	struct rtw_phl_mcc_role *m_role2 = &en_info->mcc_role[1];
	u16 d1 = 0, d2 = 0;

	/* Segment bt slot, don't support in current code*/
	if (_mcc_need_to_seg_bt_dur(minfo)) {
		/*2 wifi slot + 2bt slot*/
		d1 = m_role1->policy.dur_info.dur;
		d2 = m_role2->policy.dur_info.dur;
		en_info->mcc_intvl = WORSECASE_INTVL;
		_mcc_adjust_dur_for_2g_mcc_2role_bt(minfo);
		minfo->bt_info.bt_seg_num = 2;
		minfo->bt_info.bt_seg[0] = minfo->bt_info.bt_dur / 2;
		minfo->bt_info.bt_seg[1] = minfo->bt_info.bt_dur -
						minfo->bt_info.bt_seg[0];
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_discision_dur_for_2g_mcc_2role_bt(): Change D1(%d), D2(%d) to D1(%d), D2(%d), bt_seg[0](%d), bt_seg[1](%d)\n",
			d1, d2, m_role1->policy.dur_info.dur,
			m_role2->policy.dur_info.dur,
			minfo->bt_info.bt_seg[0], minfo->bt_info.bt_seg[1]);
	} else {
	/*2 wifi slot + 1bt slot*/
		if (minfo->bt_info.bt_dur > BT_DUR_MAX_2WS) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_discision_dur_for_2g_mcc_2role_bt(): bt req slot(%d) > BT_DUR_MAX_2WS(%d)\n",
				minfo->bt_info.bt_dur, BT_DUR_MAX_2WS);
			minfo->bt_info.bt_dur = BT_DUR_MAX_2WS;
			minfo->bt_info.bt_seg[0] = BT_DUR_MAX_2WS;
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_discision_dur_for_2g_mcc_2role_bt(): set bt rq slot to (%d)\n",
				minfo->bt_info.bt_dur);
		}
		_mcc_adjust_dur_for_2g_mcc_2role_bt(minfo);
	}
}

bool _mcc_discision_duration_for_2role_bt_v2(struct phl_mcc_info *minfo)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_bt_info *bt_info = &minfo->bt_info;
	struct rtw_phl_mcc_role *m_role1 = &en_info->mcc_role[0];
	struct rtw_phl_mcc_role *m_role2 = &en_info->mcc_role[1];
	bool add_extra_bt_role = false;

	if (bt_info->bt_dur == 0)
		goto exit;
	if (m_role1->chandef->band == BAND_ON_24G &&
		m_role2->chandef->band == BAND_ON_24G) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_discision_duration_for_2role_bt_v2(): Not support , We will ignore Bt slot\n");
#if 0
		if (_mcc_adjust_dur_for_2g_mcc_2role_bt(minfo)) {
			add_extra_bt_role = true;
		} else {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_discision_duration_for_2role_bt(): Adjust dur fail, We will ignore Bt slot\n");
		}
#endif
		goto exit;
	}
	if (m_role1->chandef->band != BAND_ON_24G &&
		m_role2->chandef->band != BAND_ON_24G) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_discision_duration_for_2role_bt_v2(): All 5G, Don't care BT duration\n");
		goto exit;
	}
	if (m_role1->chandef->band == BAND_ON_24G)
		_mcc_adjust_dur_for_2_band_mcc_2role_bt(minfo, m_role1, m_role2);
	else
		_mcc_adjust_dur_for_2_band_mcc_2role_bt(minfo, m_role2, m_role1);
exit:
	return add_extra_bt_role;
}

bool _mcc_discision_duration_for_2role_bt(struct phl_mcc_info *minfo)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *m_role1 = &en_info->mcc_role[0];
	struct rtw_phl_mcc_role *m_role2 = &en_info->mcc_role[1];
	bool add_extra_bt_role = false;

	if (minfo->bt_info.bt_dur == 0)
		goto exit;
	if (m_role1->chandef->band == BAND_ON_24G &&
		m_role2->chandef->band == BAND_ON_24G) {
		_mcc_discision_dur_for_2g_mcc_2role_bt(minfo);
		add_extra_bt_role = true;
		goto exit;
	}
	if (m_role1->chandef->band != BAND_ON_24G &&
		m_role2->chandef->band != BAND_ON_24G) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_discision_duration_for_2role_bt(): All 5G, Don't care BT duration\n");
		goto exit;
	}
	if (m_role1->chandef->band == BAND_ON_24G)
		_mcc_adjust_dur_for_2_band_mcc_2role_bt(minfo, m_role1, m_role2);
	else
		_mcc_adjust_dur_for_2_band_mcc_2role_bt(minfo, m_role2, m_role1);

exit:
	return add_extra_bt_role;
}

enum rtw_phl_status _mcc_calculate_start_tsf(struct phl_info_t *phl,
					struct rtw_phl_mcc_en_info *en_info
)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_mcc_role *ref_role = get_ref_role(en_info);
	u32 tsf_h = 0, tsf_l = 0;
	u64 tsf = 0, start_tsf = 0;
	u8 i = 0, max_loop = 10, calc_done = 0;
	u16 offset = 0;

	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_get_tsf(phl->hal,
				ref_role->wrole->hw_port, &tsf_h, &tsf_l)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_start_tsf(): Get tsf fail\n");
		goto exit;
	}
	tsf = tsf_h;
	tsf = tsf << 32;
	tsf |= tsf_l;
	/*calculate the value between current TSF and TBTT*/
	phl_calc_offset_from_tbtt(phl, ref_role->wrole, tsf, &offset);
	start_tsf = tsf - ((offset + en_info->m_pattern.tob_r) * TU);
	for (i = 0; i < max_loop; i++) {
		if (start_tsf < (tsf + (MIN_TRIGGER_MCC_TIME * TU))) {
			start_tsf += (ref_role->bcn_intvl * TU);
		} else {
			calc_done = 1;
			break;
		}
	}
	if (!calc_done) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calculate_start_tsf(): Calcculate start tsf fail, please check code flow\n");
		goto exit;
	}
	en_info->tsf_high = start_tsf >> 32;
	en_info->tsf_low = (u32)start_tsf;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_start_tsf(): start_tsf(0x%08x %08x), cur_tsf(0x%08x %08x), ref_role->bcn_intvl(%d), ref_role->duration(%d)\n",
		(u32)(start_tsf >> 32), (u32)start_tsf, (u32)(tsf >> 32),
		(u32)tsf, ref_role->bcn_intvl, ref_role->policy.dur_info.dur);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

void _mcc_set_2_clients_worsecase_default_pattern(struct rtw_phl_mcc_pattern *m_pattern,
					u16 dur_ref)
{
	m_pattern->toa_r = CLIENTS_WORSECASE_REF_TOA;
	m_pattern->tob_r = dur_ref - m_pattern->toa_r;
	_mcc_fill_slot_info(m_pattern, false,
				m_pattern->role_ref->policy.dur_info.dur,
				m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false,
				m_pattern->role_ano->policy.dur_info.dur,
				m_pattern->role_ano);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_set_2_clients_worsecase_default_pattern(): tob_r(%d), toa_r(%d)\n",
		m_pattern->tob_r, m_pattern->toa_r);
}

/*
 * get bcn offset for 2 wifi slot and 1 bt slot for pattern1
 * Pattern:
 * |      Dur_r     |     Dur_a      | Bt slot |
 *          bcn                bcn
 * | tob_r | toa_r|tob_a | toa_a| Bt slot |
 */
s16 _mcc_get_offset_for_2_wslot_1_btslot_p1(s16 dur_r,
				s16 tob_r, s16 tob_a)
{
	return dur_r - tob_r + tob_a;
}

/*
 * get bcn offset for 2 wifi slot and 1 bt slot for pattern2
 * Pattern:
 * |      Dur_r     | Bt slot |     Dur_a      |
 *          bcn                            bcn
 * | tob_r | toa_r| Bt slot |tob_a | toa_a|
 */
s16 _mcc_get_offset_for_2_wslot_1_btslot_p2(s16 dur_r, s16 bt_dur,
				s16 tob_r, s16 tob_a)
{
	return dur_r - tob_r + bt_dur + tob_a;
}

void _mcc_get_offset_range_for_2wslot_1btslot_p1(s16 ref_dur, s16 ano_dur,
				s16 *bcn_min, s16 *bcn_max)
{
	s16 min1 = 0, max1 = 0;

	*bcn_min = _mcc_get_offset_for_2_wslot_1_btslot_p1(ref_dur, EARLY_RX_BCN_T,
							EARLY_RX_BCN_T);
	*bcn_max = _mcc_get_offset_for_2_wslot_1_btslot_p1(ref_dur, EARLY_RX_BCN_T,
							ano_dur - MIN_RX_BCN_T);
	min1 = _mcc_get_offset_for_2_wslot_1_btslot_p1(ref_dur,
					ref_dur - MIN_RX_BCN_T, EARLY_RX_BCN_T);
	max1 = _mcc_get_offset_for_2_wslot_1_btslot_p1(ref_dur,
				ref_dur - MIN_RX_BCN_T, ano_dur - MIN_RX_BCN_T);
	if (min1 < *bcn_min)
		*bcn_min = min1;
	if (max1 > *bcn_max)
		*bcn_max = max1;
	PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_get_offset_range_for_2wslot_1btslot_p1(): min(%d), max(%d)\n",
		*bcn_min, *bcn_max);
}

void _mcc_get_offset_range_for_2wslot_1btslot_p2(s16 ref_dur, s16 ano_dur,
				s16 bt_dur, s16 *bcn_min, s16 *bcn_max)
{
	s16 min1 = 0, max1 = 0;

	*bcn_min = _mcc_get_offset_for_2_wslot_1_btslot_p2(ref_dur, bt_dur,
						EARLY_RX_BCN_T, EARLY_RX_BCN_T);
	*bcn_max = _mcc_get_offset_for_2_wslot_1_btslot_p2(ref_dur, bt_dur,
					EARLY_RX_BCN_T, ano_dur - MIN_RX_BCN_T);
	min1 = _mcc_get_offset_for_2_wslot_1_btslot_p2(ref_dur, bt_dur,
					ref_dur - MIN_RX_BCN_T, EARLY_RX_BCN_T);

	min1 = _mcc_get_offset_for_2_wslot_1_btslot_p2(ref_dur, bt_dur,
				ref_dur - MIN_RX_BCN_T, ano_dur - MIN_RX_BCN_T);
	if (min1 < *bcn_min)
		*bcn_min = min1;
	if (max1 > *bcn_max)
		*bcn_max = max1;
	PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_get_offset_range_for_2wslot_1btslot_p2(): min(%d), max(%d)\n",
		*bcn_min, *bcn_max);
}

s16 _mcc_get_offset_for_2_clients_worsecase(s16 ref_dur, s16 ano_dur,
				u16 ref_bcn_intvl, s16 toa_ref, s16 tob_ano)
{
	return toa_ref + tob_ano + ref_dur + ano_dur - (2 * ref_bcn_intvl);
}

void _mcc_get_offset_range_for_2_clients_worsecase(s16 ref_dur, s16 ano_dur,
				u16 ref_bcn_intvl, s16 *bcn_min, s16 *bcn_max)
{
	s16 min1 = 0, min2 = 0, max1 = 0, max2 = 0;
	min1 = _mcc_get_offset_for_2_clients_worsecase(ref_dur, ano_dur,
				ref_bcn_intvl, MIN_RX_BCN_T, EARLY_RX_BCN_T);
	max1 = _mcc_get_offset_for_2_clients_worsecase(ref_dur, ano_dur,
				ref_bcn_intvl, MIN_RX_BCN_T, ano_dur -
				MIN_RX_BCN_T);
	min2 = _mcc_get_offset_for_2_clients_worsecase(ref_dur, ano_dur,
				ref_bcn_intvl, ref_dur - EARLY_RX_BCN_T,
				EARLY_RX_BCN_T);
	max2 = _mcc_get_offset_for_2_clients_worsecase(ref_dur, ano_dur,
				ref_bcn_intvl, ref_dur -EARLY_RX_BCN_T,
				ano_dur - MIN_RX_BCN_T);
	if (min1 < min2)
		*bcn_min = min1;
	else
		*bcn_min = min2;
	if (max1 > max2)
		*bcn_max = max1;
	else
		*bcn_max = max2;
}

/*
 * copy from _mcc_calc_2wslot_1btslot_nego_p1
 * | Wifi slot1 | Bt slot | Wifi slot2 |
 */
bool _mcc_calc_2wslot_1btslot_nego_p2(struct rtw_phl_mcc_dur_info *ref_dur,
			struct rtw_phl_mcc_dur_info *ano_dur, s16 bt_dur,
			s16 offset, struct rtw_phl_mcc_pattern *m_pattern)
{
	bool cal_ok = false;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0;

	if ((ref_dur->dur_limit.enable) && (ano_dur->dur_limit.enable)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2wslot_1btslot_nego_p2(): not support, both enable slot limitation\n");
		/*todo*/
		goto exit;
	}
	if (ref_dur->dur_limit.enable) {
		tob_r = ref_dur->dur / 2;
		toa_r = ref_dur->dur - tob_r;
		if (tob_r > ref_dur->dur_limit.max_tob) {
			tob_r = ref_dur->dur_limit.max_tob;
			toa_r = ref_dur->dur - tob_r;
		}
		if (toa_r > ref_dur->dur_limit.max_toa) {
			toa_r = ref_dur->dur_limit.max_toa;
			tob_r = ref_dur->dur - toa_r;
		}
		if ((tob_r > ref_dur->dur_limit.max_tob) ||
			(toa_r > ref_dur->dur_limit.max_toa)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2wslot_1btslot_nego_p2(): After adjust tob_r(%d) > max_tob(%d) or toa_r(%d) > max_toa(%d)\n",
				tob_r, ref_dur->dur_limit.max_tob,
				toa_r, ref_dur->dur_limit.max_toa);
			goto exit;
		}
		tob_a = offset - toa_r - bt_dur;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a <= 0 || toa_a <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ref;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ano;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2wslot_1btslot_nego_p2(): Limi by ref dur, courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	} else if (ano_dur->dur_limit.enable) {
		tob_a = ano_dur->dur / 2;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a > ano_dur->dur_limit.max_tob) {
			tob_a = ano_dur->dur_limit.max_tob;
			toa_a = ano_dur->dur - tob_a;
		}
		if (toa_a > ano_dur->dur_limit.max_toa) {
			toa_a = ano_dur->dur_limit.max_toa;
			tob_a = ano_dur->dur - toa_a;
		}
		if ((tob_a > ano_dur->dur_limit.max_tob) ||
			(toa_a > ano_dur->dur_limit.max_toa)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2wslot_1btslot_nego_p2(): After adjust tob_r(%d) > max_tob(%d) or toa_r(%d) > max_toa(%d)\n",
				tob_a, ano_dur->dur_limit.max_tob,
				toa_a, ano_dur->dur_limit.max_toa);
			goto exit;
		}
		toa_r = offset - tob_a - bt_dur;
		tob_r = ref_dur->dur - toa_r;
		if (toa_r <= 0 || tob_r <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ano;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ref;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2wslot_1btslot_nego_p2(): Limi by ano dur, courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	} else {
		tob_r = ref_dur->dur / 2;
		toa_r = ref_dur->dur - tob_r;
		tob_a = offset - toa_r - bt_dur;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a <= 0 || toa_a <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ref;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ano;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2wslot_1btslot_nego_p2(): Limi by ref dur, courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	}
fill_pattern:
	cal_ok = true;
	m_pattern->tob_r = tob_r;
	m_pattern->toa_r = toa_r;
	m_pattern->tob_a = tob_a;
	m_pattern->toa_a = toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, true, bt_dur, NULL);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2wslot_1btslot_nego_p2(): calc nego patter ok(%d)\n",
		cal_ok);
	return cal_ok;
}

/*
 * copy from _mcc_calc_2_wrole_nego_pattern
 * |   Wifi slot1   |   Wifi slot2   | Bt slot |
 * |      Dur_r     |     Dur_a      | Bt slot |
 *          bcn                bcn
 * | tob_r | toa_r|tob_a | toa_a| Bt slot |
 */
bool _mcc_calc_2wslot_1btslot_nego_p1(struct rtw_phl_mcc_dur_info *ref_dur,
			struct rtw_phl_mcc_dur_info *ano_dur, s16 offset,
			s16 bt_dur, struct rtw_phl_mcc_pattern *m_pattern)
{
	bool cal_ok = false;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0;

	if ((ref_dur->dur_limit.enable) && (ano_dur->dur_limit.enable)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2wslot_1btslot_nego_p1(): not support, both enable slot limitation\n");
		/*todo*/
		goto exit;
	}
	if (ref_dur->dur_limit.enable) {
		tob_r = ref_dur->dur / 2;
		toa_r = ref_dur->dur - tob_r;
		if (tob_r > ref_dur->dur_limit.max_tob) {
			tob_r = ref_dur->dur_limit.max_tob;
			toa_r = ref_dur->dur - tob_r;
		}
		if (toa_r > ref_dur->dur_limit.max_toa) {
			toa_r = ref_dur->dur_limit.max_toa;
			tob_r = ref_dur->dur - toa_r;
		}
		if ((tob_r > ref_dur->dur_limit.max_tob) ||
			(toa_r > ref_dur->dur_limit.max_toa)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2wslot_1btslot_nego_p1(): After adjust tob_r(%d) > max_tob(%d) or toa_r(%d) > max_toa(%d)\n",
				tob_r, ref_dur->dur_limit.max_tob,
				toa_r, ref_dur->dur_limit.max_toa);
			goto exit;
		}
		tob_a = offset - toa_r;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a <= 0 || toa_a <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ref;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ano;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2wslot_1btslot_nego_p1(): Limi by ref dur, courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	} else if (ano_dur->dur_limit.enable) {
		tob_a = ano_dur->dur / 2;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a > ano_dur->dur_limit.max_tob) {
			tob_a = ano_dur->dur_limit.max_tob;
			toa_a = ano_dur->dur - tob_a;
		}
		if (toa_a > ano_dur->dur_limit.max_toa) {
			toa_a = ano_dur->dur_limit.max_toa;
			tob_a = ano_dur->dur - toa_a;
		}
		if ((tob_a > ano_dur->dur_limit.max_tob) ||
			(toa_a > ano_dur->dur_limit.max_toa)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2wslot_1btslot_nego_p1(): After adjust tob_r(%d) > max_tob(%d) or toa_r(%d) > max_toa(%d)\n",
				tob_a, ano_dur->dur_limit.max_tob,
				toa_a, ano_dur->dur_limit.max_toa);
			goto exit;
		}
		toa_r = offset - tob_a;
		tob_r = ref_dur->dur - toa_r;
		if (toa_r <= 0 || tob_r <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ano;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ref;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2wslot_1btslot_nego_p1(): Limi by ano dur, courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	} else {
		tob_r = ref_dur->dur / 2;
		toa_r = ref_dur->dur - tob_r;
		tob_a = offset - toa_r;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a <= 0 || toa_a <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ref;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ano;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2wslot_1btslot_nego_p1(): courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	}
fill_pattern:
	cal_ok = true;
	m_pattern->tob_r = tob_r;
	m_pattern->toa_r = toa_r;
	m_pattern->tob_a = tob_a;
	m_pattern->toa_a = toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
	_mcc_fill_slot_info(m_pattern, true, bt_dur, NULL);
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2wslot_1btslot_nego_p1(): calc nego patter ok(%d)\n",
		cal_ok);
	return cal_ok;
}

/*
 * copy from _mcc_calculate_2_clients_pattern
 * Calculate pattern2 for 2 wifi slot and 1 bt slot
 * Pattern:
 * |   Wifi slot1   | Bt slot |   Wifi slot2   |
 * |      Dur_r     | Bt slot |     Dur_a      |
 *          bcn                            bcn
 * | tob_r | toa_r| Bt slot |tob_a | toa_a|
 * @offset: The offset of Bcns
 * @m_pattern: pattern info
 */
enum rtw_phl_status _mcc_calculate_2wslot_1btslot_pattern2(
				struct rtw_phl_mcc_dur_info *ref_dur,
				struct rtw_phl_mcc_dur_info *ano_dur,
				u16 offset, s16 bt_dur,
				struct rtw_phl_mcc_pattern *m_pattern)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	u16 mcc_intvl = ref_dur->dur + ano_dur->dur;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0, tob_r_cand = 0;
	s16 d_r = ref_dur->dur, d_a = ano_dur->dur, bcns_offset = offset;
	s16 sum = 0, sum_last = 0;
	s16 tob_r_l = ref_dur->dur_limit.max_tob;
	s16 toa_r_l = ref_dur->dur_limit.max_toa;
	s16 tob_a_l = ano_dur->dur_limit.max_tob;
	s16 toa_a_l = ano_dur->dur_limit.max_toa;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): ref_dur(%d), ano_dur(%d), bt_dur(%d), bcns offset(%d)\n",
		d_r, d_a, bt_dur, bcns_offset);
	for (tob_r = EARLY_RX_BCN_T; tob_r < mcc_intvl; tob_r++) {
		toa_r = d_r - tob_r;
		if (toa_r < MIN_RX_BCN_T) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): break loop, by toa_r(%d) < MIN_RX_BCN_T(%d)\n",
				toa_r, MIN_RX_BCN_T);
			break;
		}
		if (ref_dur->dur_limit.enable) {
			if (tob_r > tob_r_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): tob_r(%d) > tob_r_l(%d), Break loop\n",
					tob_r, tob_r_l);
				break;
			} else if (toa_r > toa_r_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): toa_r(%d) > toa_r_l(%d), continue next loop\n",
					toa_r, toa_r_l);
				continue;
			}
		}
		tob_a = bcns_offset - toa_r - bt_dur;
		if (tob_a < EARLY_RX_BCN_T)
			continue;
		toa_a = d_a - tob_a;
		if (toa_a < MIN_RX_BCN_T){
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): break loop, by toa_a(%d) < MIN_RX_BCN_T(%d)\n",
				toa_a, MIN_RX_BCN_T);
			break;
		}
		if (ano_dur->dur_limit.enable) {
			if (tob_a > tob_a_l || toa_a > toa_a_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): tob_a(%d) > tob_a_l(%d) || toa_a(%d) > toa_a_l(%d), continue next loop\n",
					tob_a, tob_a_l, toa_a, toa_a_l);
				continue;
			}
		}
		sum = ((tob_r - toa_r) * (tob_r - toa_r)) +
			((tob_r - tob_a) * (tob_r - tob_a)) +
			((tob_r - toa_a) * (tob_r - toa_a)) +
			((toa_r - tob_a) * (toa_r - tob_a)) +
			((toa_r - toa_a) * (toa_r - toa_a)) +
			((tob_a - toa_a) * (tob_a - toa_a));
		tob_r_cand = tob_r;
		if (sum_last !=0 && sum > sum_last) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): Find the optimal pattern, by get minSum\n");
			break;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d), sum_last(%d), sum(%d)\n",
			tob_r, toa_r, tob_a, toa_a, sum_last, sum);
		sum_last = sum;
	}
	if (0 == tob_r_cand) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2wslot_1btslot_pattern2(): Can't found suitable pattern, goto calc_nego_pattern\n");
		goto exit;
	}
	tob_r = tob_r_cand;
	toa_r = d_r - tob_r;
	tob_a = bcns_offset - toa_r;
	toa_a = d_a - tob_a;
	m_pattern->tob_r = tob_r;
	m_pattern->toa_r = toa_r;
	m_pattern->tob_a = tob_a;
	m_pattern->toa_a = toa_a;
	/*Update slot order*/
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, true, bt_dur, NULL);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern2(): status(%d), tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
		status, m_pattern->tob_r, m_pattern->toa_r, m_pattern->tob_a,
		m_pattern->toa_a);
	return status;
}

/*
 * copy from _mcc_calculate_2_clients_pattern
 * Calculate pattern1 for 2 wifi slot and 1 bt slot
 * Pattern:
 * |   Wifi slot1   |   Wifi slot2   | Bt slot |
 * |      Dur_r     |     Dur_a      | Bt slot |
 *          bcn                bcn
 * | tob_r | toa_r|tob_a | toa_a| Bt slot |
 * @offset: The offset of Bcns
 * @m_pattern: pattern info
 */
enum rtw_phl_status _mcc_calculate_2wslot_1btslot_pattern1(
			struct rtw_phl_mcc_dur_info *ref_dur,
			struct rtw_phl_mcc_dur_info *ano_dur,
			u16 offset, s16 bt_dur,
			struct rtw_phl_mcc_pattern *m_pattern)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	u16 mcc_intvl = ref_dur->dur + ano_dur->dur;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0, tob_r_cand = 0;
	s16 d_r = ref_dur->dur, d_a = ano_dur->dur, bcns_offset = offset;
	s16 sum = 0, sum_last = 0;
	s16 tob_r_l = ref_dur->dur_limit.max_tob;
	s16 toa_r_l = ref_dur->dur_limit.max_toa;
	s16 tob_a_l = ano_dur->dur_limit.max_tob;
	s16 toa_a_l = ano_dur->dur_limit.max_toa;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): ref_dur(%d), ano_dur(%d), bcns offset(%d)\n",
		d_r, d_a, bcns_offset);
	for (tob_r = EARLY_RX_BCN_T; tob_r < mcc_intvl; tob_r++) {
		toa_r = d_r - tob_r;
		if (toa_r < MIN_RX_BCN_T) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): break loop, by toa_r(%d) < MIN_RX_BCN_T(%d)\n",
				toa_r, MIN_RX_BCN_T);
			break;
		}
		if (ref_dur->dur_limit.enable) {
			if (tob_r > tob_r_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): tob_r(%d) > tob_r_l(%d), Break loop\n",
					tob_r, tob_r_l);
				break;
			} else if (toa_r > toa_r_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): toa_r(%d) > toa_r_l(%d), continue next loop\n",
					toa_r, toa_r_l);
				continue;
			}
		}
		tob_a = bcns_offset - toa_r;
		if (tob_a < EARLY_RX_BCN_T)
			continue;
		toa_a = d_a - tob_a;
		if (toa_a < MIN_RX_BCN_T){
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): break loop, by toa_a(%d) < MIN_RX_BCN_T(%d)\n",
				toa_a, MIN_RX_BCN_T);
			break;
		}
		if (ano_dur->dur_limit.enable) {
			if (tob_a > tob_a_l || toa_a > toa_a_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): tob_a(%d) > tob_a_l(%d) || toa_a(%d) > toa_a_l(%d), continue next loop\n",
					tob_a, tob_a_l, toa_a, toa_a_l);
				continue;
			}
		}
		sum = ((tob_r - toa_r) * (tob_r - toa_r)) +
			((tob_r - tob_a) * (tob_r - tob_a)) +
			((tob_r - toa_a) * (tob_r - toa_a)) +
			((toa_r - tob_a) * (toa_r - tob_a)) +
			((toa_r - toa_a) * (toa_r - toa_a)) +
			((tob_a - toa_a) * (tob_a - toa_a));
		tob_r_cand = tob_r;
		if (sum_last !=0 && sum > sum_last) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): Find the optimal pattern, by get minSum\n");
			break;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d), sum_last(%d), sum(%d)\n",
			tob_r, toa_r, tob_a, toa_a, sum_last, sum);
		sum_last = sum;
	}
	if (0 == tob_r_cand) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2wslot_1btslot_pattern1(): Can't found suitable pattern, goto calc_nego_pattern\n");
		goto exit;
	}
	tob_r = tob_r_cand;
	toa_r = d_r - tob_r;
	tob_a = bcns_offset - toa_r;
	toa_a = d_a - tob_a;
	m_pattern->tob_r = tob_r;
	m_pattern->toa_r = toa_r;
	m_pattern->tob_a = tob_a;
	m_pattern->toa_a = toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
	_mcc_fill_slot_info(m_pattern, true, bt_dur, NULL);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2wslot_1btslot_pattern1(): status(%d), tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
		status, m_pattern->tob_r, m_pattern->toa_r, m_pattern->tob_a,
		m_pattern->toa_a);
	return status;
}

/*
 * Calculate pattern for 2 wifi slot and 1 bt slot
 */
enum rtw_phl_status _mcc_calculate_2wslot_1btslot_pattern(
			struct rtw_phl_mcc_dur_info *ref_dur,
			struct rtw_phl_mcc_dur_info *ano_dur,
			s16 bt_dur, struct rtw_phl_mcc_pattern *m_pattern)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	s16 offset_min = 0, offset_max = 0;
	u16 offset = m_pattern->bcns_offset;

	_mcc_get_offset_range_for_2wslot_1btslot_p1(ref_dur->dur, ano_dur->dur,
						&offset_min, &offset_max);
	if (offset >= offset_min && offset <= offset_max) {
		if (RTW_PHL_STATUS_SUCCESS !=
			_mcc_calculate_2wslot_1btslot_pattern1(ref_dur, ano_dur,
						offset, bt_dur, m_pattern)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2wslot_1btslot_pattern(): Pattern1, Can't found suitable pattern, goto calc_nego_pattern\n");
			goto calc_nego_pattern;
		} else {
			status = RTW_PHL_STATUS_SUCCESS;
			goto exit;
		}
	}
	_mcc_get_offset_range_for_2wslot_1btslot_p2(ref_dur->dur, ano_dur->dur,
					bt_dur, &offset_min, &offset_max);
	if (offset >= offset_min && offset <= offset_max) {
		if (RTW_PHL_STATUS_SUCCESS !=
			_mcc_calculate_2wslot_1btslot_pattern2(ref_dur, ano_dur,
						offset, bt_dur, m_pattern)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2wslot_1btslot_pattern(): Pattern2, Can't found suitable pattern, goto calc_nego_pattern\n");
			goto calc_nego_pattern;
		} else {
			status = RTW_PHL_STATUS_SUCCESS;
			goto exit;
		}
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2wslot_1btslot_pattern(): worsecase, goto calc_nego_pattern\n");
		goto calc_nego_pattern;
	}
calc_nego_pattern:
	if (_mcc_calc_2wslot_1btslot_nego_p1(ref_dur,
					ano_dur, offset, bt_dur, m_pattern)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2wslot_1btslot_pattern(): calc_nego_pattern1 ok\n");
	} else if (_mcc_calc_2wslot_1btslot_nego_p2(ref_dur,
					ano_dur, offset, bt_dur, m_pattern)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2wslot_1btslot_pattern(): calc_nego_pattern2 ok\n");
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calculate_2wslot_1btslot_pattern(): calc_nego_pattern fail\n");
		goto exit;
	}
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

/*
 * |Wifi1 slot| Wifi2 slot|
 * <              150TU               ><              150TU               >
 * |      Dur_r     |     Dur_a      |      Dur_r     |     Dur_a      |
 *          bcn_r                                                     bcn_a
 * | tob_r | toa_r|                                        |tob_a | toa_a|
 */
enum rtw_phl_status _mcc_calc_2_clients_worsecase_pattern(u16 ref_dur,
				u16 ano_dur, u16 offset, u16 ref_bcn_intvl,
				struct rtw_phl_mcc_pattern *m_pattern)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	u16 mcc_intvl = ref_dur + ano_dur;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0;
	s16 d_r = ref_dur, d_a = ano_dur, bcns_offset = offset;
	s16 sum = 0, sum_last = 0, offset_min = 0, offset_max = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): ref_dur(%d), ano_dur(%d), bcns offset(%d), ref_bcn_intvl(%d)\n",
		ref_dur, ano_dur, offset, ref_bcn_intvl);
	if (ref_bcn_intvl != HANDLE_BCN_INTVL) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2_clients_worsecase_pattern(): ref_bcn_intvl(%d) != HANDLE_BCN_INTVL(%d), now, we can't calculate the pattern\n",
			ref_bcn_intvl, HANDLE_BCN_INTVL);
		goto exit;
	}
	_mcc_get_offset_range_for_2_clients_worsecase(d_r, d_a, ref_bcn_intvl,
						&offset_min, &offset_max);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): we can calculate the range of bcn offset is %d~%d\n",
			offset_min, offset_max);
	if ((bcns_offset >= offset_min) && (bcns_offset <= offset_max))
		goto calc;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): transform bcn offset from %d to %d\n",
			bcns_offset, ref_bcn_intvl - bcns_offset);
	/*bcn offfset = 85, we can transform to -15*/
	bcns_offset = ref_bcn_intvl - bcns_offset;
	if (bcns_offset >= offset_min && offset_min <=offset_max) {
		goto calc;
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calculate_2_clients_worsecase_pattern(): bcn offset out of range, we can't calculate it\n");
		goto exit;
	}
calc:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): Start calculate\n");
	for (tob_r = EARLY_RX_BCN_T; tob_r < mcc_intvl; tob_r++) {
		toa_r = d_r - tob_r;
		if (toa_r < MIN_RX_BCN_T) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): Find the optimal pattern, by toa_r(%d) < MIN_RX_BCN_T(%d)\n",
				toa_r, MIN_RX_BCN_T);
			break;
		}
		tob_a = bcns_offset + 2 * ref_bcn_intvl - toa_r - mcc_intvl;
		if (tob_a < EARLY_RX_BCN_T)
			continue;
		toa_a = d_a - tob_a;
		if (toa_a < MIN_RX_BCN_T){
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): Find the optimal pattern, by toa_a(%d) < MIN_RX_BCN_T(%d)\n",
				toa_a, MIN_RX_BCN_T);
			break;
		}
		sum = ((tob_r - toa_r) * (tob_r - toa_r)) +
			((tob_r - tob_a) * (tob_r - tob_a)) +
			((tob_r - toa_a) * (tob_r - toa_a)) +
			((toa_r - tob_a) * (toa_r - tob_a)) +
			((toa_r - toa_a) * (toa_r - toa_a)) +
			((tob_a - toa_a) * (tob_a - toa_a));
		if (sum_last !=0 && sum > sum_last) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): Find the optimal pattern, by get minSum\n");
			break;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d), sum_last(%d), sum(%d)\n",
			tob_r, toa_r, tob_a, toa_a, sum_last, sum);
		sum_last = sum;

	}
	tob_r = tob_r - 1;
	toa_r = d_r - tob_r;
	tob_a = bcns_offset + 2 * ref_bcn_intvl - toa_r - mcc_intvl;
	toa_a = d_a - tob_a;
	m_pattern->tob_r = (u8)tob_r;
	m_pattern->toa_r = (u8)toa_r;
	m_pattern->tob_a = (u8)tob_a;
	m_pattern->toa_a = (u8)toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur, m_pattern->role_ano);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_worsecase_pattern(): Result, tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
			tob_r, toa_r, tob_a, toa_a);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	if (status != RTW_PHL_STATUS_SUCCESS)
		m_pattern->calc_fail = true;
	return status;
}

#if 0
void _mcc_fill_bt_slot(struct phl_mcc_info *minfo,
				struct rtw_phl_mcc_dur_info *ref_dur,
				struct rtw_phl_mcc_dur_info *ano_dur)
{
	struct rtw_phl_mcc_bt_info *bt_info = &minfo->bt_info;
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_pattern *m_pattern = &en_info->m_pattern;
	u8 i = 0;
	s16 spacing = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_fill_bt_slot()\n");
	if (false == bt_info->add_bt_role)
		goto exit;
	spacing = m_pattern->bcns_offset - m_pattern->toa_r - m_pattern->tob_a;
	if (0 < spacing) {
		if (bt_info->bt_dur < spacing) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_bt_slot(): bt_info->bt_dur(%d) < spacing(%d), adjust BT dur to (%d), please check code\n",
				bt_info->bt_dur, spacing, spacing);
			bt_info->bt_dur = spacing;
			bt_info->bt_seg[0] = bt_info->bt_dur;
			bt_info->bt_seg_num = 1;
			goto exit;
		}
		bt_info->bt_seg[0] = spacing;
		bt_info->bt_seg[1] = bt_info->bt_dur - bt_info->bt_seg[0];
		bt_info->bt_seg_num = 2;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_bt_slot(): Segment Bt dur to Seg1(%d), Seg2(%d)\n",
			bt_info->bt_seg[0], bt_info->bt_seg[1]);
	} else if (0 == spacing){
		bt_info->bt_seg[0] = bt_info->bt_dur;
		bt_info->bt_seg_num = 1;
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_bt_slot(): spacing(%d) < 0, please check code,\n",
			spacing);
	}
exit:
	_mcc_dump_bt_ino(bt_info);
	return;
}
#endif

/*
 * |Wifi1 slot|Wifi2 slot|
 */
bool _mcc_calc_2_wrole_nego_pattern(struct rtw_phl_mcc_dur_info *ref_dur,
				struct rtw_phl_mcc_dur_info *ano_dur, s16 offset,
				struct rtw_phl_mcc_pattern *m_pattern)
{
	bool cal_ok = false;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0;

	if ((!ref_dur->dur_limit.enable) && (!ano_dur->dur_limit.enable)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2_wrole_nego_pattern(): not support, both not enable slot limitation\n");
		/*todo*/
		goto exit;
	}
	if ((ref_dur->dur_limit.enable) && (ano_dur->dur_limit.enable)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2_wrole_nego_pattern(): not support, both enable slot limitation\n");
		/*todo*/
		goto exit;
	}
	if ((ref_dur->dur_limit.enable) && (!ano_dur->dur_limit.enable)) {
		tob_r = ref_dur->dur / 2;
		toa_r = ref_dur->dur - tob_r;
		if (tob_r > ref_dur->dur_limit.max_tob) {
			tob_r = ref_dur->dur_limit.max_tob;
			toa_r = ref_dur->dur - tob_r;
		}
		if (toa_r > ref_dur->dur_limit.max_toa) {
			toa_r = ref_dur->dur_limit.max_toa;
			tob_r = ref_dur->dur - toa_r;
		}
		if ((tob_r > ref_dur->dur_limit.max_tob) ||
			(toa_r > ref_dur->dur_limit.max_toa)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2_wrole_nego_pattern(): After adjust tob_r(%d) > max_tob(%d) or toa_r(%d) > max_toa(%d)\n",
				tob_r, ref_dur->dur_limit.max_tob,
				toa_r, ref_dur->dur_limit.max_toa);
			goto exit;
		}
		tob_a = offset - toa_r;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a <= 0 || toa_a <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ref;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ano;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2_wrole_nego_pattern(): Limi by ref dur, courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	}
	if ((!ref_dur->dur_limit.enable) && (ano_dur->dur_limit.enable)) {
		tob_a = ano_dur->dur / 2;
		toa_a = ano_dur->dur - tob_a;
		if (tob_a > ano_dur->dur_limit.max_tob) {
			tob_a = ano_dur->dur_limit.max_tob;
			toa_a = ano_dur->dur - tob_a;
		}
		if (toa_a > ano_dur->dur_limit.max_toa) {
			toa_a = ano_dur->dur_limit.max_toa;
			tob_a = ano_dur->dur - toa_a;
		}
		if ((tob_a > ano_dur->dur_limit.max_tob) ||
			(toa_a > ano_dur->dur_limit.max_toa)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2_wrole_nego_pattern(): After adjust tob_r(%d) > max_tob(%d) or toa_r(%d) > max_toa(%d)\n",
				tob_a, ano_dur->dur_limit.max_tob,
				toa_a, ano_dur->dur_limit.max_toa);
			goto exit;
		}
		toa_r = offset - tob_a;
		tob_r = ref_dur->dur - toa_r;
		if (toa_r <= 0 || tob_r <= 0) {
			m_pattern->courtesy_i.c_en= true;
			m_pattern->courtesy_i.c_num = 3;
			m_pattern->courtesy_i.src_role = m_pattern->role_ano;
			m_pattern->courtesy_i.tgt_role = m_pattern->role_ref;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2_wrole_nego_pattern(): Limi by ano dur, courtesy_info: c_en(%d), c_num(%d), src_role->macid(0x%x), tgt_role->macid(0x%x)\n",
				m_pattern->courtesy_i.c_en,
				m_pattern->courtesy_i.c_num,
				m_pattern->courtesy_i.src_role->macid,
				m_pattern->courtesy_i.tgt_role->macid);
		}
		goto fill_pattern;
	}
fill_pattern:
	cal_ok = true;
	m_pattern->tob_r = tob_r;
	m_pattern->toa_r = toa_r;
	m_pattern->tob_a = tob_a;
	m_pattern->toa_a = toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wrole_nego_pattern(): calc nego patter\n");
exit:
	return cal_ok;
}

#if 0
/**
 * Calculate the optimal pattern for 2wrole MCC with limitation of time slot v2
 * @ref_dur: Duration info of reference ch
 * @ano_dur: Duration info of another ch
 * @offset: The offset between beacon of ref_role and beacon of ano_role
 * @m_pattern: mcc pattern.
 **/
enum rtw_phl_status _mcc_calculate_2_wrole_pattern_v2(
				struct rtw_phl_mcc_dur_info *ref_dur,
				struct rtw_phl_mcc_dur_info *ano_dur,
				u16 offset,
				struct rtw_phl_mcc_pattern *m_pattern)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0;
	s16 tob_r_cand = 0, toa_r_cand = 0, tob_a_cand = 0, toa_a_cand = 0;
	s16 d_r = ref_dur->dur, d_a = ano_dur->dur, bcns_offset = offset;
	s16 sum = 0, sum_last = 0;
	s16 tob_r_min = _mcc_is_ap_category(m_pattern->role_ref->wrole) ?
			EARLY_TX_BCN_T : EARLY_RX_BCN_T;
	s16 toa_r_min = _mcc_is_ap_category(m_pattern->role_ref->wrole) ?
			MIN_TX_BCN_T : MIN_RX_BCN_T;
	s16 tob_a_min = _mcc_is_ap_category(m_pattern->role_ano->wrole) ?
			EARLY_TX_BCN_T : EARLY_RX_BCN_T;
	s16 toa_a_min = _mcc_is_ap_category(m_pattern->role_ano->wrole) ?
			MIN_TX_BCN_T : MIN_RX_BCN_T;
	s16 min_bcns_offset = toa_r_min + tob_a_min;
	s16 i = 0, cnt = 0;
	bool bdry_r = false, bdry_a = false; /*reach boundary edge*/

	if ((bcns_offset > (m_pattern->role_ref->bcn_intvl - min_bcns_offset))
		|| (bcns_offset < min_bcns_offset)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2_wrole_pattern_v2(): bcns_offset(%d) > max_offset(%d) || bcns_offset < min_offset(%d), goto calc_nego_pattern\n",
			bcns_offset,
			(m_pattern->role_ref->bcn_intvl - min_bcns_offset),
			min_bcns_offset);
		goto calc_nego_pattern;
	}
	cnt = bcns_offset - toa_r_min - tob_a_min;
	toa_r = toa_r_min;
	tob_a = tob_a_min;
	for (i = 0; i < cnt; i++) {
		if ((true == bdry_r) && (true == bdry_a)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2_wrole_pattern_v2(): braek loop by (true == bdry_r) && (true == bdry_a)\n");
			break;
		}
		if (true == bdry_r)
			goto calc_ano;
		if (i > 0)
			toa_r++;
		tob_r = d_r - toa_r;
		if (tob_r < tob_r_min) {
			bdry_r = true;
			goto calc_ano;
		}
		if (!ref_dur->dur_limit.enable)
			goto check_conflict1;
		if ((tob_r > ref_dur->dur_limit.max_tob) ||
			(toa_r > ref_dur->dur_limit.max_toa)) {
			goto calc_ano;
		}
check_conflict1:
		if ((toa_r + tob_a_cand) > bcns_offset) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2_wrole_pattern_v2(): braek loop by conflict(toa_r(%d) + tob_a_cand(%d)) > bcns_offset(%d)\n",
				toa_r, tob_a_cand, bcns_offset);
			break;
		}
		toa_r_cand = toa_r;
calc_ano:
		if (true == bdry_a)
			continue;
		if (i > 0)
			tob_a++;
		toa_a = d_a - tob_a;
		if (toa_a < toa_a_min) {
			bdry_a = true;
			continue;
		}
		if (!ano_dur->dur_limit.enable)
			goto check_conflict2;
		if ((tob_a > ano_dur->dur_limit.max_tob) ||
			(toa_a > ano_dur->dur_limit.max_toa)) {
			continue;
		}
check_conflict2:
		if ((bcns_offset - (tob_a + toa_r_cand)) >
			(m_pattern->d_r_d_a_spacing_max)) {
			continue;
		}
		if ((tob_a + toa_r_cand) > bcns_offset) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2_wrole_pattern_v2(): braek loop by conflict(tob_a(%d) + toa_r_cand(%d)) > bcns_offset(%d)\n",
				tob_a, toa_r_cand, bcns_offset);
			break;
		}
		tob_a_cand = tob_a;
/*calculate candidate result*/
		tob_r_cand = d_r - toa_r_cand;
		toa_a_cand = d_a - tob_a_cand;
		sum = ((tob_r_cand - toa_r_cand) * (tob_r_cand - toa_r_cand)) +
		      ((tob_r_cand - tob_a_cand) * (tob_r_cand - tob_a_cand)) +
		      ((tob_r_cand - toa_a_cand) * (tob_r_cand - toa_a_cand)) +
		      ((toa_r_cand - tob_a_cand) * (toa_r_cand - tob_a_cand)) +
		      ((toa_r_cand - toa_a_cand) * (toa_r_cand - toa_a_cand)) +
		      ((tob_a_cand - toa_a_cand) * (tob_a_cand - toa_a_cand));
		if (sum_last !=0 && sum > sum_last) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern_v2(): Find the optimal pattern, by get minSum\n");
			break;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern_v2(): tob_r_cand(%d), toa_r_cand(%d), tob_a_cand(%d), toa_a_cand(%d), sum_last(%d), sum(%d)\n",
			tob_r_cand, toa_r_cand, tob_a_cand, toa_a_cand,
			sum_last, sum);
		sum_last = sum;
	}
	if ((0 == toa_r_cand) || (0 == tob_a_cand)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2_wrole_pattern_v2(): Can't found suitable pattern, goto calc_nego_pattern\n");
		goto calc_nego_pattern;
	}
	m_pattern->tob_r = tob_r_cand;
	m_pattern->toa_r = toa_r_cand;
	m_pattern->tob_a = tob_a_cand;
	m_pattern->toa_a = toa_a_cand;
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
calc_nego_pattern:
	if (_mcc_calc_2_wrole_nego_pattern(ref_dur, ano_dur, bcns_offset,
						m_pattern)) {
		status = RTW_PHL_STATUS_SUCCESS;
	}
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern_v2(): m_pattern: tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
		m_pattern->tob_r, m_pattern->toa_r, m_pattern->tob_a,
		m_pattern->toa_a);
	return status;
}
#endif

#if 0
/**
 * Copy from _mcc_calc_2_clients_worsecase_pattern and add limitation of time slot
 * worsecase: TDMA interval is 150 TU
 * Calculate the optimal pattern for 2wifi slot with limitation of time slot for worsecase
 * @ref_dur: Duration info of reference slot
 * @ano_dur: Duration info of another slot
 * @offset: The offset between beacon of ref_role and beacon of ano_role
 * @ref_bcn_intvl: Bcn interval of reference role
 * @m_pattern: mcc pattern.
 **/
enum rtw_phl_status _mcc_calc_2_wifi_slot_worsecase_pattern(
			struct rtw_phl_mcc_dur_info *ref_dur,
			struct rtw_phl_mcc_dur_info *ano_dur, u16 offset,
			u16 ref_bcn_intvl, struct rtw_phl_mcc_pattern *m_pattern)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	u16 mcc_intvl = ref_dur->dur + ano_dur->dur;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0, tob_r_cand = 0;

	s16 d_r = ref_dur->dur, d_a = ano_dur->dur, bcns_offset = offset;
	s16 sum = 0, sum_last = 0, offset_min = 0, offset_max = 0;
	s16 tob_r_l = ref_dur->dur_limit.max_tob;
	s16 toa_r_l = ref_dur->dur_limit.max_toa;
	s16 tob_a_l = ano_dur->dur_limit.max_tob;
	s16 toa_a_l = ano_dur->dur_limit.max_toa;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): ref_dur(%d), ano_dur(%d), bcns offset(%d), ref_bcn_intvl(%d)\n",
		d_r, d_a, offset, ref_bcn_intvl);
	if (ref_bcn_intvl != HANDLE_BCN_INTVL) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): ref_bcn_intvl(%d) != HANDLE_BCN_INTVL(%d), now, we can't calculate the pattern\n",
			ref_bcn_intvl, HANDLE_BCN_INTVL);
		goto exit;
	}
	_mcc_get_offset_range_for_2_clients_worsecase(d_r, d_a, ref_bcn_intvl,
						&offset_min, &offset_max);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): we can calculate the range of bcn offset is %d~%d\n",
			offset_min, offset_max);
	if ((bcns_offset >= offset_min) && (bcns_offset <= offset_max))
		goto calc;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): transform bcn offset from %d to %d\n",
			bcns_offset, ref_bcn_intvl - bcns_offset);
	/*bcn offfset = 85, we can transform to -15*/
	bcns_offset = ref_bcn_intvl - bcns_offset;
	if (bcns_offset >= offset_min && offset_min <=offset_max) {
		goto calc;
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): bcn offset out of range, we can't calculate it\n");
		goto exit;
	}
calc:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): Start calculate\n");
	for (tob_r = EARLY_RX_BCN_T; tob_r < mcc_intvl; tob_r++) {
		toa_r = d_r - tob_r;
		if (toa_r < MIN_RX_BCN_T) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): Break loop, by toa_r(%d) < MIN_RX_BCN_T(%d)\n",
				toa_r, MIN_RX_BCN_T);
			break;
		}
		if (ref_dur->dur_limit.enable) {
			if (toa_r > toa_r_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): toa_r(%d) > toa_r_l(%d), continue next loop\n",
					toa_r, toa_r_l);
				continue;
			}
			if (tob_r > tob_r_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): Break loop, tob_r(%d) > tob_r_l(%d)\n",
					tob_r, tob_r_l);
				break;
			}
		}
		tob_a = bcns_offset + 2 * ref_bcn_intvl - toa_r - mcc_intvl;
		if (tob_a < EARLY_RX_BCN_T)
			continue;
		toa_a = d_a - tob_a;
		if (toa_a < MIN_RX_BCN_T){
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): Break loop, by toa_a(%d) < MIN_RX_BCN_T(%d)\n",
				toa_a, MIN_RX_BCN_T);
			break;
		}
		if (ano_dur->dur_limit.enable) {
			if (tob_a > tob_a_l || toa_a > toa_a_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): tob_a(%d) > tob_a_l(%d) || toa_a(%d) > toa_a_l(%d), continue next loop\n",
					tob_a, tob_a_l, toa_a, toa_a_l);
				continue;
			}
		}
		sum = ((tob_r - toa_r) * (tob_r - toa_r)) +
			((tob_r - tob_a) * (tob_r - tob_a)) +
			((tob_r - toa_a) * (tob_r - toa_a)) +
			((toa_r - tob_a) * (toa_r - tob_a)) +
			((toa_r - toa_a) * (toa_r - toa_a)) +
			((tob_a - toa_a) * (tob_a - toa_a));
		tob_r_cand = tob_r;
		if (sum_last !=0 && sum > sum_last) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): Find the optimal pattern, by get minSum\n");
			break;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d), sum_last(%d), sum(%d)\n",
			tob_r, toa_r, tob_a, toa_a, sum_last, sum);
		sum_last = sum;

	}
	if (0 == tob_r_cand) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): Can't found suitable pattern, goto calc_nego_pattern\n");
		goto calc_nego_pattern;
	}
	tob_r = tob_r_cand;
	toa_r = d_r - tob_r;
	tob_a = bcns_offset + 2 * ref_bcn_intvl - toa_r - mcc_intvl;
	toa_a = d_a - tob_a;
	m_pattern->tob_r = tob_r;
	m_pattern->toa_r = toa_r;
	m_pattern->tob_a = tob_a;
	m_pattern->toa_a = toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): Result, tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
			tob_r, toa_r, tob_a, toa_a);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
calc_nego_pattern:
	if (_mcc_calc_2_wrole_nego_pattern(ref_dur, ano_dur, bcns_offset,
					m_pattern))
		status = RTW_PHL_STATUS_SUCCESS;
exit:
	if (status != RTW_PHL_STATUS_SUCCESS)
		m_pattern->calc_fail = true;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calc_2_wifi_slot_worsecase_pattern(): status(%d)\n",
		status);
	return status;
}
#endif

/*
 * Calculate the optimal pattern for 2wrole MCC with limitation of time slot
 * @ref_dur: Duration of reference ch
 * @ano_dur: Duration of another ch
 * @offset: The offset between beacon of client1 and beacon of client2
 * @m_pattern: mcc pattern.
 * |          Wifi1 slot        |            Wifi2 slot        |          Wifi1 slot        |             Wifi2 slot        |
 * <tob_r> Bcn_r <toa_r>                                   <tob_r> Bcn_r <toa_r>
 *                                  <tob_a> Bcn_a <toa_a>                                  <tob_a> Bcn_a <toa_a>
 *	         <       bcns_offset       >
 */
enum rtw_phl_status _mcc_calculate_2_wrole_pattern(
				struct rtw_phl_mcc_dur_info *ref_dur,
				struct rtw_phl_mcc_dur_info *ano_dur,
				u16 offset,
				struct rtw_phl_mcc_pattern *m_pattern)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	u16 mcc_intvl = ref_dur->dur + ano_dur->dur;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0, tob_r_cand = 0;
	s16 d_r = ref_dur->dur, d_a = ano_dur->dur, bcns_offset = offset;
	s16 sum = 0, sum_last = 0;
	s16 tob_r_l = ref_dur->dur_limit.max_tob;
	s16 toa_r_l = ref_dur->dur_limit.max_toa;
	s16 tob_a_l = ano_dur->dur_limit.max_tob;
	s16 toa_a_l = ano_dur->dur_limit.max_toa;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern(): ref_dur(%d), ano_dur(%d), bcns offset(%d)\n",
		d_r, d_a, bcns_offset);
	for (tob_r = EARLY_RX_BCN_T; tob_r < mcc_intvl; tob_r++) {
		toa_r = d_r - tob_r;
		if (toa_r < MIN_RX_BCN_T) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern(): break loop, by toa_r(%d) < MIN_RX_BCN_T(%d)\n",
				toa_r, MIN_RX_BCN_T);
			break;
		}
		if (ref_dur->dur_limit.enable) {
			if (tob_r > tob_r_l || toa_r > toa_r_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern(): tob_r(%d) > tob_r_l(%d) || toa_r(%d) > toa_r_l(%d), continue next loop\n",
					tob_r, tob_r_l, toa_r, toa_r_l);
				continue;
			}
		}
		tob_a = bcns_offset - toa_r;
		if (tob_a < EARLY_RX_BCN_T)
			continue;
		toa_a = d_a - tob_a;
		if (toa_a < MIN_RX_BCN_T){
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern(): break loop, by toa_a(%d) < MIN_RX_BCN_T(%d)\n",
				toa_a, MIN_RX_BCN_T);
			break;
		}
		if (ano_dur->dur_limit.enable) {
			if (tob_a > tob_a_l || toa_a > toa_a_l) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern(): tob_a(%d) > tob_a_l(%d) || toa_a(%d) > toa_a_l(%d), continue next loop\n",
					tob_a, tob_a_l, toa_a, toa_a_l);
				continue;
			}
		}
		sum = ((tob_r - toa_r) * (tob_r - toa_r)) +
			((tob_r - tob_a) * (tob_r - tob_a)) +
			((tob_r - toa_a) * (tob_r - toa_a)) +
			((toa_r - tob_a) * (toa_r - tob_a)) +
			((toa_r - toa_a) * (toa_r - toa_a)) +
			((tob_a - toa_a) * (tob_a - toa_a));
		tob_r_cand = tob_r;
		if (sum_last !=0 && sum > sum_last) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern(): Find the optimal pattern, by get minSum\n");
			break;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_wrole_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d), sum_last(%d), sum(%d)\n",
			tob_r, toa_r, tob_a, toa_a, sum_last, sum);
		sum_last = sum;
	}
	if (0 == tob_r_cand) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_calculate_2_wrole_pattern(): Can't found suitable pattern, goto calc_nego_pattern\n");
		goto calc_nego_pattern;
	}
	tob_r = tob_r_cand;
	toa_r = d_r - tob_r;
	tob_a = bcns_offset - toa_r;
	toa_a = d_a - tob_a;
	m_pattern->tob_r = tob_r;
	m_pattern->toa_r = toa_r;
	m_pattern->tob_a = tob_a;
	m_pattern->toa_a = toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur->dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur->dur, m_pattern->role_ano);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
calc_nego_pattern:
	if (_mcc_calc_2_wrole_nego_pattern(ref_dur, ano_dur, bcns_offset,
					m_pattern))
		status = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
			m_pattern->tob_r, m_pattern->toa_r, m_pattern->tob_a,
			m_pattern->toa_a);
	return status;
}

/*
 * Calculate the optimal pattern for client+client MCC
 * @ref_dur: Duration of reference ch
 * @ano_dur: Duration of another ch
 * @offset: The offset between beacon of client1 and beacon of client2
 * @m_pattern: mcc pattern.
 * |          Wifi1 slot        |            Wifi2 slot        |          Wifi1 slot        |             Wifi2 slot        |
 * <tob_r> Bcn_r <toa_r>                                   <tob_r> Bcn_r <toa_r>
 *                                  <tob_a> Bcn_a <toa_a>                                  <tob_a> Bcn_a <toa_a>
 *	         <       bcns_offset       >
 */
void _mcc_calculate_2_clients_pattern(u16 ref_dur, u16 ano_dur, u16 offset,
					struct rtw_phl_mcc_pattern *m_pattern)
{
	u16 mcc_intvl = ref_dur + ano_dur;
	s16 tob_r = 0, toa_r = 0, tob_a = 0, toa_a = 0;
	s16 d_r = ref_dur, d_a = ano_dur, bcns_offset = offset;
	s16 sum = 0, sum_last = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_pattern(): ref_dur(%d), ano_dur(%d), bcns offset(%d)\n",
		ref_dur, ano_dur, offset);
	for (tob_r = EARLY_RX_BCN_T; tob_r < mcc_intvl; tob_r++) {
		toa_r = d_r - tob_r;
		if (toa_r < MIN_RX_BCN_T) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_pattern(): Find the optimal pattern, by toa_r(%d) < MIN_RX_BCN_T(%d)\n",
				toa_r, MIN_RX_BCN_T);
			break;
		}
		tob_a = bcns_offset - toa_r;
		if (tob_a < EARLY_RX_BCN_T)
			continue;
		toa_a = d_a - tob_a;
		if (toa_a < MIN_RX_BCN_T){
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_pattern(): Find the optimal pattern, by toa_a(%d) < MIN_RX_BCN_T(%d)\n",
				toa_a, MIN_RX_BCN_T);
			break;
		}
		sum = ((tob_r - toa_r) * (tob_r - toa_r)) +
			((tob_r - tob_a) * (tob_r - tob_a)) +
			((tob_r - toa_a) * (tob_r - toa_a)) +
			((toa_r - tob_a) * (toa_r - tob_a)) +
			((toa_r - toa_a) * (toa_r - toa_a)) +
			((tob_a - toa_a) * (tob_a - toa_a));
		if (sum_last !=0 && sum > sum_last) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_pattern(): Find the optimal pattern, by get minSum\n");
			break;
		}
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d), sum_last(%d), sum(%d)\n",
			tob_r, toa_r, tob_a, toa_a, sum_last, sum);
		sum_last = sum;
	}
	tob_r = tob_r - 1;
	toa_r = d_r - tob_r;
	tob_a = bcns_offset - toa_r;
	toa_a = d_a - tob_a;
	m_pattern->tob_r = (u8)tob_r;
	m_pattern->toa_r = (u8)toa_r;
	m_pattern->tob_a = (u8)tob_a;
	m_pattern->toa_a = (u8)toa_a;
	_mcc_fill_slot_info(m_pattern, false, ref_dur, m_pattern->role_ref);
	_mcc_fill_slot_info(m_pattern, false, ano_dur, m_pattern->role_ano);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_calculate_2_clients_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
			tob_r, toa_r, tob_a, toa_a);
}

/*
 * Fill patten info for 2wifi slot req + bt slot req
 * @minfo: enable mcc info
 * @role_ref: reference wifi slot req
 * @role_ano: another wifi slot req
 */
void _mcc_fill_2_wrole_bt_pattern(struct phl_mcc_info *minfo,
	struct rtw_phl_mcc_role *role_ref, struct rtw_phl_mcc_role *role_ano)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_pattern *m_pattern = &en_info->m_pattern;
	struct rtw_phl_mcc_dur_info dur_ref = role_ref->policy.dur_info;
	struct rtw_phl_mcc_dur_info dur_ano = role_ano->policy.dur_info;
#if 0
	u16 dr_max = (dur_ref.dur_limit.enable) ?
			dur_ref.dur_limit.max_dur : en_info->mcc_intvl;
	u16 da_max = (dur_ano.dur_limit.enable) ?
			dur_ano.dur_limit.max_dur : en_info->mcc_intvl;


	if (minfo->bt_info.bt_seg_num == 2) {
		/*temporary disable this case, we can't handle it in GC(NOA)+STA*/
		minfo->bt_info.add_bt_role = true;
		if (((dur_ref.dur + minfo->bt_info.bt_seg[0]) <= dr_max) &&
			((dur_ano.dur + minfo->bt_info.bt_seg[1]) <= da_max)) {
			dur_ref.dur += minfo->bt_info.bt_seg[0];
			dur_ano.dur += minfo->bt_info.bt_seg[1];
		} else if ((dur_ref.dur + minfo->bt_info.bt_dur) <= dr_max) {
			dur_ref.dur += minfo->bt_info.bt_dur;
		} else if ((dur_ano.dur + minfo->bt_info.bt_dur) <= da_max) {
			dur_ano.dur += minfo->bt_info.bt_dur;
		} else {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_2_wrole_bt_pattern(): Fail to combine wifi slot and bt slot to single slot, we use default worsecase pattern \n");
			_mcc_set_2_clients_worsecase_default_pattern(m_pattern, dur_ref.dur);
			goto exit;
		}
		if (RTW_PHL_STATUS_SUCCESS !=
				_mcc_calc_2_wifi_slot_worsecase_pattern(
						&dur_ref, &dur_ano,
						m_pattern->bcns_offset,
						role_ref->bcn_intvl,
						m_pattern)) {
			_mcc_set_2_clients_worsecase_default_pattern(m_pattern, dur_ref.dur);
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_2_wrole_bt_pattern(): _mcc_calc_2_wifi_slot_worsecase_pattern fail, we use default worsecase pattern\n");
		}
		dur_ref = role_ref->policy.dur_info;
		dur_ano = role_ano->policy.dur_info;
		if (m_pattern->tob_r > (dur_ref.dur - MIN_RX_BCN_T)) {
			role_ref->policy.protect_bcn = true;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_2_wrole_bt_pattern(): bcn will in bt dur, we set protect_bcn = true for role_ref\n");
		}
		if (m_pattern->tob_a > (dur_ano.dur - MIN_RX_BCN_T)) {
			role_ano->policy.protect_bcn = true;
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_2_wrole_bt_pattern(): bcn will in bt dur, we set protect_bcn = true for role_ano\n");
		}
	} else
#endif
	if (minfo->bt_info.bt_seg_num == 1) {
		minfo->bt_info.add_bt_role = true;
		if (RTW_PHL_STATUS_SUCCESS !=
			_mcc_calculate_2wslot_1btslot_pattern(&dur_ref,
				&dur_ano, minfo->bt_info.bt_dur, m_pattern)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_2_wrole_bt_pattern(): _mcc_calculate_2wslot_1btslot_pattern fail, we use default worsecase pattern\n");
			_mcc_set_2_clients_worsecase_default_pattern(m_pattern, dur_ref.dur);
		}
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_2_wrole_bt_pattern(): error bt_seg_num(%d)\n",
			minfo->bt_info.bt_seg_num);
	}
#if 0
exit:
#endif
	return;
}

bool _mcc_fill_2wrole_pattern_with_limitation(struct phl_mcc_info *minfo,
	struct rtw_phl_mcc_role *role_ref, struct rtw_phl_mcc_role *role_ano)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_dur_info *dur_i_r = &role_ref->policy.dur_info;
	struct rtw_phl_mcc_dur_info *dur_i_a = &role_ano->policy.dur_info;
	struct rtw_phl_mcc_policy_info *policy_i = NULL;
	struct rtw_phl_mcc_courtesy *courtesy_i = &en_info->m_pattern.courtesy_i;
	bool ret = false;

	if (!(dur_i_r->dur_limit.enable || dur_i_a->dur_limit.enable))
		goto exit;
	if (dur_i_r->dur_limit.enable && dur_i_a->dur_limit.enable) {
		/*implement in phase????*/
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_2wrole_pattern_with_limitation(): Not support for all enable limitation, tag_r(%d), tag_a(%d)\n",
			dur_i_r->dur_limit.tag, dur_i_a->dur_limit.tag);
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_2wrole_pattern_with_limitation(): we ignore the limitation of time slot, it will degrade performance\n");
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_fill_2wrole_pattern_with_limitation\n");
	if (_mcc_discision_duration_for_2role_bt(minfo)) {
		_mcc_fill_2_wrole_bt_pattern(minfo, role_ref,  role_ano);
	} else if (RTW_PHL_STATUS_SUCCESS != _mcc_calculate_2_wrole_pattern(
					dur_i_r, dur_i_a,
					en_info->m_pattern.bcns_offset,
					&en_info->m_pattern)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_2wrole_pattern_with_limitation(): Calc pattern fail with limitation of time slot, we ignore the limitation of time slot, it will degrade performance\n");
		goto exit;
	}
	/*_mcc_fill_bt_slot(minfo, dur_i_r, dur_i_a);*/
	if (true == courtesy_i->c_en) {
		policy_i = &courtesy_i->src_role->policy;
		policy_i->courtesy_en = true;
		policy_i->courtesy_num = courtesy_i->c_num;
		policy_i->courtesy_target = (u8)courtesy_i->tgt_role->macid;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_2wrole_pattern_with_limitation(): Enable courtesy function, time slot of macid:0x%x replace by time slot of macid:0x%x, courtesy_num(%d)\n",
			courtesy_i->src_role->macid, policy_i->courtesy_target,
			policy_i->courtesy_num);
	}
	ret =true;
exit:
	return ret;
}

void _mcc_fill_2_clients_pattern(struct phl_mcc_info *minfo, u8 worsecase,
	struct rtw_phl_mcc_role *role_ref, struct rtw_phl_mcc_role *role_ano)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;

	if (!worsecase) {
		_mcc_calculate_2_clients_pattern(role_ref->policy.dur_info.dur,
						role_ano->policy.dur_info.dur,
						en_info->m_pattern.bcns_offset,
						&en_info->m_pattern);
		goto exit;
	}
	if (RTW_PHL_STATUS_SUCCESS != _mcc_calc_2_clients_worsecase_pattern(
					role_ref->policy.dur_info.dur,
					role_ano->policy.dur_info.dur,
					en_info->m_pattern.bcns_offset,
					role_ref->bcn_intvl,
					&en_info->m_pattern)) {
		_mcc_set_2_clients_worsecase_default_pattern(&en_info->m_pattern,
						role_ref->policy.dur_info.dur);
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_info_for_2_clients_mode(): _mcc_calc_2_clients_worsecase_pattern fail, we use default worsecase pattern\n");
	}
exit:
	return;
}

enum rtw_phl_status _mcc_get_2_clients_bcn_offset(struct phl_info_t *phl,
			u16 *offset, struct rtw_phl_mcc_role *role_ref,
			struct rtw_phl_mcc_role *role_ano)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	u32 tsf_ref_h = 0, tsf_ref_l = 0, tsf_ano_h = 0, tsf_ano_l = 0;
	u64 tsf_ref = 0, tsf_ano = 0;
	u16 ofst_r = 0, ofst_a = 0;

	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_get_2ports_tsf(phl->hal,
			role_ref->group, role_ref->macid, role_ano->macid,
			&tsf_ref_h, &tsf_ref_l, &tsf_ano_h, &tsf_ano_l)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_get_2_clients_bcn_offset(): Get tsf failed\n");
		goto exit;
	}
	tsf_ref = tsf_ref_h;
	tsf_ref = tsf_ref << 32;
	tsf_ref |= tsf_ref_l;
	tsf_ano = tsf_ano_h;
	tsf_ano = tsf_ano << 32;
	tsf_ano |= tsf_ano_l;
	/*calculate the value between current TSF and TBTT*/
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_get_2_clients_bcn_offset(): role_ref calc_offset_from_tbtt\n");
	phl_calc_offset_from_tbtt(phl, role_ref->wrole, tsf_ref, &ofst_r);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_get_2_clients_bcn_offset(): role_ano calc_offset_from_tbtt\n");
	phl_calc_offset_from_tbtt(phl, role_ano->wrole, tsf_ano, &ofst_a);
	if (ofst_r < ofst_a)
		ofst_r += role_ref->bcn_intvl;
	*offset = ofst_r - ofst_a;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_get_2_clients_bcn_offset(): bcn offset(%d)\n",
		*offset);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

/**
* set defalut pattern for ap slot+sta slot
 * |       Wifi1 slot           |          Wifi2 slot         |       Wifi1 slot           |          Wifi2 slot         |
 * <tob_r> Bcn_r <toa_r>                                  <tob_r> Bcn_r <toa_r>
 *                                  <tob_a> Bcn_a <toa_a>                                 <tob_a> Bcn_a <toa_a>
 *               <         bcns_offset         >
 **/

void _mcc_set_ap_client_default_pattern(struct phl_mcc_info *minfo,
					u16 *bcns_offet)
{
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_pattern *m_pattern = &en_info->m_pattern;
	struct rtw_phl_mcc_role *role_ref = get_ref_role(en_info);
	struct rtw_phl_mcc_role *role_ano = (role_ref == &en_info->mcc_role[0])
				? &en_info->mcc_role[1] : &en_info->mcc_role[0];

	*bcns_offet = (u8)(en_info->mcc_intvl / 2);
	m_pattern->toa_r= role_ref->policy.dur_info.dur / 2;
	m_pattern->tob_r = role_ref->policy.dur_info.dur - m_pattern->toa_r;
	m_pattern->tob_a = (u8)(*bcns_offet - m_pattern->toa_r);
	m_pattern->toa_a = role_ano->policy.dur_info.dur - m_pattern->tob_a;
	_mcc_fill_slot_info(m_pattern, false, role_ref->policy.dur_info.dur, role_ref);
	_mcc_fill_slot_info(m_pattern, false, role_ano->policy.dur_info.dur, role_ano);
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_set_ap_client_default_pattern(): tob_r(%d), toa_r(%d), tob_a(%d), toa_a(%d)\n",
		m_pattern->tob_r, m_pattern->toa_r, m_pattern->tob_a, m_pattern->toa_a);
}

void _mcc_set_worsecase_dur_for_2_clients_mode(
				struct rtw_phl_mcc_dur_info *dur_i_1,
				struct rtw_phl_mcc_dur_info *dur_i_2,
				u16 *mcc_intvl)
{
	/*need to get from core layer for worsecase??*/
	if (dur_i_1->dur > dur_i_2->dur) {
		*mcc_intvl = WORSECASE_INTVL;
		dur_i_1->dur = CLIENTS_WORSECASE_LARGE_DUR;
		dur_i_2->dur = (*mcc_intvl - dur_i_1->dur);
	} else {
		*mcc_intvl = WORSECASE_INTVL;
		dur_i_2->dur = CLIENTS_WORSECASE_LARGE_DUR;
		dur_i_1->dur = (*mcc_intvl - dur_i_2->dur);
	}
}

void _mcc_set_dur_for_2_clients_mode(
				struct rtw_phl_mcc_dur_info *dur_i_1,
				struct rtw_phl_mcc_dur_info *dur_i_2,
				u16 *mcc_intvl)
{
	u16 *dur1 = &dur_i_1->dur, *dur2 = &dur_i_2->dur;

	if (*dur1 == MCC_DUR_NONSPECIFIC) {
		*dur1 = (*mcc_intvl - (*dur2));
	} else {
		*dur2 = (*mcc_intvl - (*dur1));
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_set_dur_for_2_clients_mode(): Original dur1(%d), dur2(%d)\n",
		*dur1, *dur2);
	if (*dur1 < MIN_CLIENT_DUR) {
		*dur1 = MIN_CLIENT_DUR;
		*dur2 = (*mcc_intvl - (*dur1));
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_set_dur_for_2_clients_mode(): Core specific unsuitable duration, we adjust dur to dur1(%d) and dur2(%d)\n",
			*dur1, *dur2);
	} else if (*dur2 < MIN_CLIENT_DUR) {
		*dur2 = MIN_CLIENT_DUR;
		*dur1 = (*mcc_intvl - (*dur2));
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_set_dur_for_2_clients_mode(): Core specific unsuitable duration, we adjust dur to dur1(%d) and dur2(%d)\n",
			*dur1, *dur2);
	}
	if ((dur_i_1->dur_limit.enable) && (dur_i_1->dur_limit.max_dur != 0) &&
		(*dur1 > dur_i_1->dur_limit.max_dur)) {
		*dur1 = dur_i_1->dur_limit.max_dur;
		*dur2 = (*mcc_intvl - (*dur1));
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_set_dur_for_2_clients_mode(): dur1 > max_dur(%d), we adjust dur to dur1(%d) and dur2(%d)\n",
			dur_i_1->dur_limit.max_dur, *dur1, *dur2);
	}
	if ((dur_i_2->dur_limit.enable) && (dur_i_2->dur_limit.max_dur != 0) &&
		(*dur2 > dur_i_2->dur_limit.max_dur)) {
		*dur2 = dur_i_2->dur_limit.max_dur;
		*dur1 = (*mcc_intvl - (*dur2));
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_set_dur_for_2_clients_mode(): dur2 > max_dur(%d), we adjust dur to dur1(%d) and dur2(%d)\n",
			dur_i_2->dur_limit.max_dur, *dur1, *dur2);
	}
}

enum rtw_phl_status _mcc_fill_info_for_2_clients_mode(struct phl_info_t *phl,
						struct phl_mcc_info *minfo)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *role_ref = get_ref_role(en_info);
	struct rtw_phl_mcc_role *role_ano = (role_ref == &en_info->mcc_role[0])
				? &en_info->mcc_role[1] : &en_info->mcc_role[0];
	u16 bcns_offset = 0;
	bool worsecase = false;

	en_info->mcc_intvl = role_ref->bcn_intvl;
	if (RTW_PHL_STATUS_SUCCESS != _mcc_get_2_clients_bcn_offset(phl,
					&bcns_offset, role_ref, role_ano)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_info_for_2_clients_mode(): Get bcn offset fail\n");
		goto exit;
	}
	en_info->m_pattern.role_ref = role_ref;
	en_info->m_pattern.role_ano = role_ano;
	en_info->m_pattern.bcns_offset = bcns_offset;
	if ((bcns_offset < MIN_BCNS_OFFSET) ||
		(bcns_offset > (role_ref->bcn_intvl - MIN_BCNS_OFFSET))) {
		worsecase = true;
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_fill_info_for_2_clients_mode(): worsecase, bcns_offset(%d) < %d or bcns_offset > %d\n",
			bcns_offset, MIN_BCNS_OFFSET,
			(role_ref->bcn_intvl - MIN_BCNS_OFFSET));
	}
	_mcc_set_dur_for_2_clients_mode(&role_ref->policy.dur_info,
					&role_ano->policy.dur_info,
					&en_info->mcc_intvl);
	if (_mcc_fill_2wrole_pattern_with_limitation(minfo, role_ref, role_ano)) {
		/*wifi slot, bt slot, and only 1 wifi slot with limitation*/
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_info_for_2_clients_mode(): _mcc_fill_2wrole_pattern_with_limitation\n");
	} else if (_mcc_discision_duration_for_2role_bt(minfo)) {
		_mcc_fill_2_wrole_bt_pattern(minfo, role_ref, role_ano);
	} else {
	/*We only adjust dur for all wifi slot in worsecase*/
		if (worsecase) {
			_mcc_set_worsecase_dur_for_2_clients_mode(
				&role_ref->policy.dur_info,
				&role_ano->policy.dur_info, &en_info->mcc_intvl);
		}
		_mcc_fill_2_clients_pattern(minfo, worsecase, role_ref, role_ano);
	}
	if (RTW_PHL_STATUS_SUCCESS != _mcc_calculate_start_tsf(phl, en_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_info_for_2_clients_mode(): calculate start tsf fail\n");
		goto exit;
	}
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

void _mcc_set_dur_for_ap_client_mode(u16 *ap_dur, u16 *client_dur, u16 mcc_intvl)
{
	if (*ap_dur == MCC_DUR_NONSPECIFIC)
		*ap_dur = mcc_intvl - *client_dur;
	if (*ap_dur < MIN_AP_DUR) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_set_dur_for_ap_client_mode(): ap_dur(%d) < MIN_AP_DUR(%d), set ap_dur = MIN_AP_DUR\n",
			*ap_dur, MIN_AP_DUR);
		*ap_dur = MIN_AP_DUR;
	} else if (*ap_dur > (mcc_intvl - MIN_CLIENT_DUR)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_WARNING_, "_mcc_set_dur_for_ap_client_mode(): ap_dur(%d) < MAX_AP_DUR(%d), set ap_dur = MAX_AP_DUR\n",
			*ap_dur, (mcc_intvl - MIN_CLIENT_DUR));
		*ap_dur = mcc_intvl - MIN_CLIENT_DUR;
	}
	*client_dur = mcc_intvl - *ap_dur;
}

enum rtw_phl_status _mcc_fill_info_for_ap_client_mode(
			struct phl_info_t *phl, struct phl_mcc_info *minfo)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_sync_tsf_info *sync_info = &en_info->sync_tsf_info;
	struct rtw_phl_mcc_role *ap_role = NULL;
	struct rtw_phl_mcc_role *client_role = NULL;
	struct rtw_phl_mcc_role *role_ref = get_ref_role(en_info);
	struct rtw_phl_mcc_role *role_ano = (role_ref == &en_info->mcc_role[0])
				? &en_info->mcc_role[1] : &en_info->mcc_role[0];

	ap_role = _mcc_get_mrole_by_category(en_info, MCC_ROLE_AP_CAT);
	client_role = _mcc_get_mrole_by_category(en_info, MCC_ROLE_CLIENT_CAT);
	if (ap_role == NULL || client_role == NULL) {
		_mcc_dump_en_info(en_info);
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_info_for_ap_client_mode(): (ap_role == NULL || client_role == NULL)\n");
		goto exit;
	}
	en_info->m_pattern.role_ref = role_ref;
	en_info->m_pattern.role_ano = role_ano;
	en_info->mcc_intvl = ap_role->bcn_intvl;
	_mcc_set_dur_for_ap_client_mode(&ap_role->policy.dur_info.dur,
					&client_role->policy.dur_info.dur,
					en_info->mcc_intvl);
	if (_mcc_discision_duration_for_2role_bt(minfo)) {
		en_info->m_pattern.bcns_offset = AP_CLIENT_OFFSET;
		_mcc_fill_2_wrole_bt_pattern(minfo, role_ref, role_ano);
	} else {
		_mcc_set_ap_client_default_pattern(minfo,
					&en_info->m_pattern.bcns_offset);
	}
	if (RTW_PHL_STATUS_SUCCESS != rtw_phl_tbtt_sync(phl,
					client_role->wrole, ap_role->wrole,
					en_info->m_pattern.bcns_offset, true,
					&sync_info->offset)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_info_for_ap_client_mode(): Sync tsf fail\n");
		goto exit;
	}
	sync_info->source = client_role->macid;
	sync_info->target = ap_role->macid;
	sync_info->sync_en = true;
	if (RTW_PHL_STATUS_SUCCESS != _mcc_calculate_start_tsf(phl, en_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_info_for_ap_client_mode(): calculate start tsf fail\n");
		goto exit;
	}
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

/*
 * |         Wifi slot          |          BT slot         |
 * <tob_r> Bcn_r <toa_r>
**/
enum rtw_phl_status _mcc_fill_info_for_ap_bt_mode(
			struct phl_info_t *phl, struct phl_mcc_info *minfo)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_mcc_en_info *en_info = &minfo->en_info;
	struct rtw_phl_mcc_role *role_ref = get_ref_role(en_info);
	struct rtw_phl_mcc_pattern *m_pattern = &en_info->m_pattern;

	minfo->bt_info.add_bt_role = true;
	en_info->mcc_intvl = role_ref->bcn_intvl;
	role_ref->policy.dur_info.dur = (u8)(en_info->mcc_intvl -
							minfo->bt_info.bt_dur);
	m_pattern->role_ref = role_ref;
	m_pattern->toa_r= role_ref->policy.dur_info.dur / 2;
	m_pattern->tob_r = role_ref->policy.dur_info.dur - m_pattern->toa_r;
	_mcc_fill_slot_info(m_pattern, false, role_ref->policy.dur_info.dur, role_ref);
	_mcc_fill_slot_info(m_pattern, true, minfo->bt_info.bt_dur, NULL);
	if (RTW_PHL_STATUS_SUCCESS != _mcc_calculate_start_tsf(phl, en_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_info_for_ap_bt_mode(): calculate start tsf fail\n");
		goto exit;
	}
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

enum rtw_phl_status _mcc_pkt_offload_for_client(struct phl_info_t *phl, u8 macid)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_stainfo_t *phl_sta = NULL;
	struct rtw_pkt_ofld_null_info null_info = {0};
	void *d = phl_to_drvpriv(phl);
	u32 null_token = 0;

	phl_sta = rtw_phl_get_stainfo_by_macid(phl, macid);
	if (phl_sta == NULL) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_pkt_offload_for_client(): get sta fail, macid(%d)\n",
			macid);
		goto exit;
	}
	if (NOT_USED != phl_pkt_ofld_get_id(phl, macid,
						PKT_TYPE_NULL_DATA)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_pkt_offload_for_client(): macid(%d), we had already offload NULL Pkt\n",
			macid);
		status = RTW_PHL_STATUS_SUCCESS;
		goto exit;
	}
	_os_mem_cpy(d, &(null_info.a1[0]), &(phl_sta->mac_addr[0]),
		MAC_ADDRESS_LENGTH);
	_os_mem_cpy(d,&(null_info.a2[0]), &(phl_sta->wrole->mac_addr[0]),
		MAC_ADDRESS_LENGTH);
	_os_mem_cpy(d, &(null_info.a3[0]), &(phl_sta->mac_addr[0]),
		MAC_ADDRESS_LENGTH);
	if (RTW_PHL_STATUS_SUCCESS != phl_pkt_ofld_request(phl, macid,
						PKT_TYPE_NULL_DATA, &null_token,
						__func__, &null_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_pkt_offload_for_client(): Pkt offload fail, macid(%d)\n",
			macid);
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_pkt_offload_for_client(): offload ok, macid(%d), null_token(%d)\n",
		macid, null_token);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}


enum rtw_phl_status _mcc_pkt_offload(struct phl_info_t *phl,
					struct rtw_phl_mcc_en_info *info)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_mcc_role *mcc_role = NULL;
	u8 midx = 0;

	for (midx = 0; midx < MCC_ROLE_NUM; midx++) {
		if (!(info->mrole_map & BIT(midx)))
			continue;
		mcc_role = &info->mcc_role[midx];
		if (_mcc_is_client_category(mcc_role->wrole)) {
			if (RTW_PHL_STATUS_SUCCESS !=
				_mcc_pkt_offload_for_client(phl,
							(u8)mcc_role->macid)) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_pkt_offload_for_client(): mcc_role index(%d)\n",
					midx);
				goto exit;
			}
		}
	}
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

enum rtw_phl_status _mcc_update_2_clients_pattern(struct phl_info_t *phl,
				struct phl_mcc_info *ori_minfo,
				struct phl_mcc_info *new_minfo)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;

	if (RTW_PHL_STATUS_SUCCESS != _mcc_fill_info_for_2_clients_mode(phl,
								new_minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_2_clients_pattern(): fill info fail for 2clients mode\n");
		goto error;
	}
	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_change_pattern(phl->hal,
					&ori_minfo->en_info, &new_minfo->en_info,
					&new_minfo->bt_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_2_clients_pattern(): set duration fail\n");
		goto error;
	}
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
error:
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_2_clients_pattern(): Update fail\n");
exit:
	return status;
}

enum rtw_phl_status _mcc_update_ap_client_pattern(struct phl_info_t *phl,
		struct phl_mcc_info *ori_minfo, struct phl_mcc_info *new_minfo)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;

	if (RTW_PHL_STATUS_SUCCESS != _mcc_fill_info_for_ap_client_mode(phl,
								new_minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_ap_client_pattern(): fill info fail for ap client mode\n");
		goto error;
	}
	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_change_pattern(phl->hal,
					&ori_minfo->en_info, &new_minfo->en_info,
					&new_minfo->bt_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_ap_client_pattern(): set duration fail\n");
		goto error;
	}
	if ((new_minfo->en_info.sync_tsf_info.sync_en) &&
		(new_minfo->en_info.sync_tsf_info.offset !=
		ori_minfo->en_info.sync_tsf_info.offset)) {
		if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_sync_enable(phl->hal,
							&new_minfo->en_info)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_ap_client_pattern(): set tsf sync fail\n");
			goto error;
		}
	}
	_mcc_up_noa(phl, new_minfo);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
error:
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_ap_client_pattern(): Update fail\n");
exit:
	return status;
}

enum rtw_phl_status _mcc_update_ap_bt_pattern(struct phl_info_t *phl,
		struct phl_mcc_info *ori_minfo, struct phl_mcc_info *new_minfo)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;

	if (RTW_PHL_STATUS_SUCCESS != _mcc_fill_info_for_ap_bt_mode(phl,
								new_minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_ap_bt_pattern(): fill info fail for ap_bt\n");
		goto error;
	}
	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_change_pattern(phl->hal,
					&ori_minfo->en_info, &new_minfo->en_info,
					&new_minfo->bt_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_ap_bt_pattern(): set duration fail\n");
		goto error;
	}
	_mcc_up_noa(phl, new_minfo);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
error:
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_update_ap_bt_pattern(): Update fail\n");
exit:
	return status;
}

enum rtw_phl_status _mcc_duration_change(struct phl_info_t *phl,
		struct phl_mcc_info *minfo, struct phl_mcc_info *new_minfo)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;

	if (RTW_PHL_TDMRA_AP_CLIENT_WMODE == minfo->mcc_mode) {
		if (RTW_PHL_STATUS_SUCCESS != _mcc_update_ap_client_pattern(
					phl, minfo, new_minfo)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_duration_change(): update ap_client fail\n");
			goto exit;
		}
	} else if (RTW_PHL_TDMRA_2CLIENTS_WMODE == minfo->mcc_mode) {
		if (RTW_PHL_STATUS_SUCCESS != _mcc_update_2_clients_pattern(
							phl, minfo, new_minfo)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_duration_change(): update ap_client fail\n");
			goto exit;
		}
	} else if (RTW_PHL_TDMRA_AP_WMODE == minfo->mcc_mode) {
		if (RTW_PHL_STATUS_SUCCESS != _mcc_update_ap_bt_pattern(
							phl, minfo, new_minfo)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_duration_change(): update ap_bt fail\n");
			goto exit;
		}
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_duration_change(): Undefined mcc_mode(%d)\n",
			minfo->mcc_mode);
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_duration_change(): Update success\n");
	_os_mem_cpy(phl_to_drvpriv(phl), minfo, new_minfo,
			sizeof(struct phl_mcc_info));
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

void _mcc_2_clients_tracking(struct phl_info_t *phl,
				struct phl_mcc_info *minfo
)
{
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct rtw_phl_mcc_pattern *m_pattern = NULL;
	struct rtw_phl_mcc_role *role_ref = NULL;
	struct rtw_phl_mcc_role *role_ano = NULL;
	struct phl_mcc_info new_minfo = {0};
	u16 bcns_offset = 0, diff = 0, tol = 0;/*tolerance*/
	bool negative_sign = false;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_2_clients_tracking\n");
	_os_mem_cpy(phl_to_drvpriv(phl), &new_minfo, minfo,
			sizeof(struct phl_mcc_info));
	en_info = &new_minfo.en_info;
	m_pattern = &en_info->m_pattern;
	role_ref = get_ref_role(en_info);
	role_ano = (role_ref == &en_info->mcc_role[0]) ? &en_info->mcc_role[1] :
							&en_info->mcc_role[0];
	if (RTW_PHL_STATUS_SUCCESS != _mcc_get_2_clients_bcn_offset(phl,
					&bcns_offset, role_ref, role_ano)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_2_clients_tracking(): Get bcn offset fail\n");
		goto exit;
	}
	if (bcns_offset > m_pattern->bcns_offset) {
		diff = bcns_offset - m_pattern->bcns_offset;
	} else {
		diff = m_pattern->bcns_offset - bcns_offset;
		negative_sign = true;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_2_clients_tracking(): old bcns_offset(%d), new bcns_offset(%d)\n",
		m_pattern->bcns_offset, bcns_offset);
	_mcc_dump_pattern(m_pattern);
	_mcc_dump_ref_role_info(en_info);
	if (en_info->m_pattern.courtesy_i.c_en) {
		tol = CLIENTS_TRACKING_COURTESY_TH;
		goto decision;
	}
	if (en_info->mcc_intvl == WORSECASE_INTVL) {
		tol = CLIENTS_TRACKING_WORSECASE_TH;
		goto decision;
	}
	if (negative_sign) {
		if (m_pattern->tob_a <= EARLY_RX_BCN_T) {
			tol = CLIENTS_TRACKING_CRITICAL_POINT_TH;
		} else if (m_pattern->tob_a >= (2 * EARLY_RX_BCN_T)){
			tol = m_pattern->tob_a - ((3 * EARLY_RX_BCN_T) / 2);
		} else {
			tol = CLIENTS_TRACKING_TH;
		}
	} else {
		if (m_pattern->toa_a <= MIN_RX_BCN_T) {
			tol = CLIENTS_TRACKING_CRITICAL_POINT_TH;
		} else if (m_pattern->toa_a >= (2 * MIN_RX_BCN_T)){
			tol = m_pattern->toa_a - ((3 * MIN_RX_BCN_T) / 2);
		} else {
			tol = CLIENTS_TRACKING_TH;
		}
	}
decision:
	if (diff < tol)
		goto exit;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_2_clients_tracking(): Need to update new 2clients pattern, negative_sign(%d), diff(%d), tolerance(%d), mcc_intvl(%d)\n",
		negative_sign, diff, tol, en_info->mcc_intvl);
	_mcc_reset_minfo(phl, &new_minfo, MINFO_RESET_BT_INFO |
						MINFO_RESET_PATTERN_INFO);
	/*fill original bt slot*/
	_mcc_fill_bt_dur(phl, &new_minfo);
	/*get original wifi time slot*/
	_mcc_fill_mcc_role_policy_info(phl, role_ref->wrole, role_ref);
	_mcc_fill_mcc_role_policy_info(phl, role_ano->wrole, role_ano);
	if (RTW_PHL_STATUS_SUCCESS != _mcc_update_2_clients_pattern(phl,
							minfo, &new_minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_2_clients_tracking(): update 2clients fail\n");
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_2_clients_tracking(): update new pattern ok\n");
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_2_clients_tracking(): old pattern:\n");
	_mcc_dump_pattern(&en_info->m_pattern);
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_2_clients_tracking(): new pattern:\n");
	_mcc_dump_pattern(&new_minfo.en_info.m_pattern);
	_os_mem_cpy(phl_to_drvpriv(phl), minfo, &new_minfo,
			sizeof(struct phl_mcc_info));
exit:
	return;
}

enum rtw_phl_status rtw_phl_mcc_ap_bt_coex_enable(struct phl_info_t *phl,
				struct rtw_wifi_role_t *cur_role)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, cur_role->hw_band);

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_ap_bt_coex_enable(): cur_role->type(%d)\n",
		cur_role->type);
	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, cur_role->hw_band);
	en_info = &minfo->en_info;
	if (MCC_NONE != minfo->state && MCC_STOP != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): (MCC_NONE != minfo->state || MCC_STOP != minfo->state(%d)), please check code flow\n",
			minfo->state);
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	_mcc_set_state(minfo, MCC_CFG_EN_INFO);
	_mcc_reset_minfo(phl, minfo, (MINFO_RESET_EN_INFO | MINFO_RESET_MODE |
				MINFO_RESET_ROLE_MAP | MINFO_RESET_COEX_MODE |
				MINFO_RESET_BT_INFO));
	if (RTW_PHL_STATUS_SUCCESS != _mcc_get_role_map(phl, band_ctrl,
							&minfo->role_map)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): Get role map failed\n");
		goto _cfg_info_fail;
	}
	if (RTW_PHL_STATUS_SUCCESS != _mcc_transfer_mode(phl, minfo,
							minfo->role_map)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): transfer mcc mode failed\n");
		goto _cfg_info_fail;
	}
	if (RTW_PHL_TDMRA_AP_WMODE != minfo->mcc_mode) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): error  wmode\n");
		_mcc_dump_mode(&minfo->mcc_mode);
		goto _cfg_info_fail;
	}
	if (RTW_PHL_STATUS_SUCCESS != _mcc_fill_role_info(phl, en_info,
						minfo->role_map, cur_role)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): fill role info failed\n");
		goto _cfg_info_fail;
	}
	_mcc_fill_coex_mode(phl, minfo);
	_mcc_fill_bt_dur(phl, minfo);
	if (RTW_PHL_STATUS_SUCCESS != _mcc_get_mrole_idx_by_wrole(minfo,
					cur_role, &en_info->ref_role_idx)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): fill ref_role idx failed\n");
		goto _cfg_info_fail;
	}
	if (RTW_PHL_STATUS_SUCCESS != _mcc_fill_info_for_ap_bt_mode(phl, minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): fill ref_role idx failed\n");
		goto _cfg_info_fail;
	}
	_mcc_set_state(minfo, MCC_TRIGGER_FW_EN);
	if (rtw_hal_mcc_enable(phl->hal, en_info, &minfo->bt_info) !=
						RTW_HAL_STATUS_SUCCESS) {
		_mcc_set_state(minfo, MCC_FW_EN_FAIL);
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_ap_bt_coex_enable(): Enable FW mcc Fail\n");
		goto exit;
	}
	_mcc_set_state(minfo, MCC_RUNING);
	PHL_TRACE(COMP_PHL_MCC, _PHL_ALWAYS_, "rtw_phl_mcc_ap_bt_coex_enable(): Enable FW mcc ok\n");
	_mcc_up_noa(phl, minfo);
	_mcc_dump_mcc_info(minfo);
	_mcc_up_fw_log_setting(phl, minfo);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
_cfg_info_fail:
	_mcc_set_state(minfo, MCC_NONE);
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_ALWAYS_, "<<< rtw_phl_mcc_ap_bt_coex_enable():status(%d)\n",
		status);
	return status;
}

enum rtw_phl_status rtw_phl_mcc_go_bt_coex_disable(struct phl_info_t *phl,
				struct rtw_wifi_role_t *spec_role)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct rtw_phl_mcc_role *m_role = NULL;

	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_go_bt_coex_disable(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, spec_role->hw_band);
	en_info = &minfo->en_info;
	if (MCC_RUNING != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_go_bt_coex_disable(): MCC_RUNING != m_info->state, please check code flow\n");
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	if (NULL == (m_role = _mcc_get_mrole_by_wrole(minfo, spec_role))) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_go_bt_coex_disable(): Can't get mrole, wrole id(%d), please check code flow\n",
			spec_role->id);
		goto exit;
	}
	_mcc_set_state(minfo, MCC_TRIGGER_FW_DIS);
	if (rtw_hal_mcc_disable(phl->hal, m_role->group, m_role->macid)
						!= RTW_HAL_STATUS_SUCCESS) {
		status = RTW_PHL_STATUS_FAILURE;
		_mcc_set_state(minfo, MCC_FW_DIS_FAIL);
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_,"rtw_phl_mcc_go_bt_coex_disable(): Disable FW mcc Fail\n");
		goto exit;
	}
	rtw_hal_sync_cur_ch(phl->hal, spec_role->hw_band, spec_role->chandef);
	_mcc_set_state(minfo, MCC_STOP);
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_go_bt_coex_disable(): Disable FW mcc ok\n");
	_mcc_clean_noa(phl, en_info);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_ALWAYS_, "<<< rtw_phl_mcc_go_bt_coex_disable(): status(%d)\n",
		status);
	return status;
}

void rtw_phl_mcc_watchdog(struct phl_info_t *phl, u8 band_idx)
{
	struct phl_mcc_info *minfo = NULL;

	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_watchdog(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, band_idx);
	if (MCC_RUNING != minfo->state)
		goto exit;

	if (RTW_PHL_TDMRA_2CLIENTS_WMODE == minfo->mcc_mode)
		_mcc_2_clients_tracking(phl, minfo);

exit:
	return;
}

enum rtw_phl_status rtw_phl_mcc_duration_change(struct phl_info_t *phl,
			struct phl_tdmra_dur_change_info *info)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = get_mcc_info(phl, info->hw_band);
	struct phl_mcc_info new_minfo = {0};
	struct rtw_phl_mcc_role *spec_mrole = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_duration_change\n");
	_os_mem_cpy(phl_to_drvpriv(phl), &new_minfo, minfo,
			sizeof(struct phl_mcc_info));
	_mcc_set_unspecific_dur(&new_minfo);
	spec_mrole = _mcc_get_mrole_by_wrole(&new_minfo, info->role);
	if (NULL == spec_mrole) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_duration_change(): Can't get mrole by wrole(%d), please check code flow\n",
			info->role->id);
		goto exit;
	}
	spec_mrole->policy.dur_info.dur = info->dur;
	if (RTW_PHL_STATUS_SUCCESS != _mcc_duration_change(phl, minfo,
								&new_minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_duration_change(): Change fail\n");
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_duration_change(): Change success\n");
	status = RTW_PHL_STATUS_SUCCESS;
	_mcc_dump_mcc_info(&new_minfo);
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< rtw_phl_mcc_duration_change\n");
	return status;
}

enum rtw_phl_status rtw_phl_mcc_bt_duration_change(struct phl_info_t *phl,
				struct phl_tdmra_dur_change_info *info)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = get_mcc_info(phl, info->hw_band);
	struct phl_mcc_info new_minfo = {0};
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct rtw_phl_mcc_role *mrole = NULL;
	u8 midx = 0;
	bool exist_2g = false;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_bt_duration_change(): dur(%d)\n",
		info->dur);
	if (info->dur == minfo->bt_info.bt_dur) {
		status = RTW_PHL_STATUS_SUCCESS;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_phl_mcc_bt_duration_change(): no change of bt slot(%d), skip it\n",
			info->dur);
		goto exit;
	}
	_os_mem_cpy(phl_to_drvpriv(phl), &new_minfo, minfo,
			sizeof(struct phl_mcc_info));
	en_info = &new_minfo.en_info;
	_mcc_reset_minfo(phl, &new_minfo, MINFO_RESET_BT_INFO |
						MINFO_RESET_PATTERN_INFO);
	_mcc_fill_bt_dur(phl, &new_minfo);
	/*fill original wifi time slot*/
	for (midx = 0; midx < en_info->mrole_num; midx++) {
		if (!(en_info->mrole_map & BIT(midx)))
			continue;
		mrole = &en_info->mcc_role[midx];
		_mcc_fill_mcc_role_policy_info(phl, mrole->wrole, mrole);
		if (mrole->chandef->band == BAND_ON_24G)
			exist_2g = true;
	}
	if (false == exist_2g) {
		status = RTW_PHL_STATUS_SUCCESS;
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_phl_mcc_bt_duration_change(): All 5G, Don't care BT duration\n");
		goto exit;
	}
	if (RTW_PHL_STATUS_SUCCESS != _mcc_duration_change(phl, minfo,
								&new_minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_bt_duration_change(): Change fail\n");
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_bt_duration_change(): Change success\n");
	status = RTW_PHL_STATUS_SUCCESS;
	_mcc_dump_mcc_info(&new_minfo);
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< rtw_phl_mcc_bt_duration_change(): status(%d)\n",
		status);
	return status;
}

enum rtw_phl_status rtw_phl_mcc_dur_lim_change(struct phl_info_t *phl,
				struct rtw_wifi_role_t *wrole,
				struct phl_mcc_dur_lim_req_info *lim_req)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = NULL;
	struct phl_mcc_info new_minfo = {0};
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct rtw_phl_mcc_role *spec_mrole = NULL;
	struct rtw_phl_mcc_role *mrole = NULL;
	u8 midx = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_dur_lim_change()\n");
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_fill_dur_lim_info(): dur_req: tag(%d), enable(%d), start_t_h(0x%08x), start_t_l(0x%08x), dur(%d), intvl(%d)\n",
		lim_req->tag, lim_req->enable, lim_req->start_t_h,
		lim_req->start_t_l, lim_req->dur, lim_req->intvl);

	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_dur_lim_change(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, wrole->hw_band);
	if (MCC_RUNING != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_dur_lim_change(): MCC_RUNING != minfo->state, , please check code flow\n");
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	_os_mem_cpy(phl_to_drvpriv(phl), &new_minfo, minfo,
			sizeof(struct phl_mcc_info));
	spec_mrole = _mcc_get_mrole_by_wrole(&new_minfo, wrole);
	if (NULL == spec_mrole) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_dur_lim_change(): Can't get mrole by wrole(%d), please check code flow\n",
			wrole->id);
		goto exit;
	}
	en_info = &new_minfo.en_info;
	/*fill original bt slot*/
	_mcc_reset_minfo(phl, &new_minfo, MINFO_RESET_BT_INFO |
						MINFO_RESET_PATTERN_INFO);
	_mcc_fill_bt_dur(phl, &new_minfo);
	/*fill original wifi time slot*/
	for (midx = 0; midx < en_info->mrole_num; midx++) {
		if (!(en_info->mrole_map & BIT(midx)))
			continue;
		mrole = &en_info->mcc_role[midx];
		_mcc_fill_mcc_role_policy_info(phl, mrole->wrole, mrole);
	}
	_mcc_fill_dur_lim_info(phl, spec_mrole, lim_req);
	if (RTW_PHL_STATUS_SUCCESS != _mcc_duration_change(phl, minfo,
								&new_minfo)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_dur_lim_change(): Change fail\n");
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_dur_lim_change(): Change success\n");
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

void rtw_phl_mcc_sta_entry_change(struct phl_info_t *phl,
					struct rtw_wifi_role_t *wrole)
{
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_role *mrole = NULL;

	if (!is_mcc_init(phl)) {
		goto exit;
	}
	minfo = get_mcc_info(phl, wrole->hw_band);
	if (MCC_RUNING != minfo->state) {
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, ">>> rtw_phl_mcc_sta_entry_change\n");
	minfo = get_mcc_info(phl, wrole->hw_band);
	if (NULL == (mrole = _mcc_get_mrole_by_wrole(minfo, wrole))) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_sta_entry_change(): Can't get mrole, wrole id(%d), please check code flow\n",
			wrole->id);
		goto exit;
	}
	_mcc_fill_macid_bitmap_by_role(phl, mrole);
	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_update_macid_bitmap(
					phl->hal, mrole->group,
					mrole->macid, &mrole->used_macid)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_sta_entry_change(): Update macid map fail\n");
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_sta_entry_change(): Update macid map ok\n");
	_mcc_dump_mcc_info(minfo);
exit:
	return;
}

void phl_mcc_client_link_notify_for_ap(struct phl_info_t *phl,
			struct rtw_wifi_role_t *wrole, enum role_state state)
{
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_role *mrole = NULL;

	if (state != PHL_ROLE_MSTS_STA_CONN_START &&
		state != PHL_ROLE_MSTS_STA_DIS_CONN)
		goto exit;
	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s(): mcc is not init, please check code\n",
			__func__);
		goto exit;
	}
	minfo = get_mcc_info(phl, wrole->hw_band);
	if (MCC_RUNING != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s(): MCC_RUNING != minfo->state\n",
			__func__);
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	if (NULL == (mrole = _mcc_get_mrole_by_wrole(minfo, wrole))) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s(): Can't get mrole, wrole id(%d), please check code flow\n",
			__func__, wrole->id);
		goto exit;
	}
	_mcc_fill_macid_bitmap_by_role(phl, mrole);
	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mcc_update_macid_bitmap(
					phl->hal, mrole->group,
					mrole->macid, &mrole->used_macid)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s(): Update macid map fail\n",
			__func__);
		goto exit;
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s(): Update macid map ok\n",
		__func__);
	_mcc_dump_mcc_info(minfo);
exit:
	return;
}

bool rtw_phl_mcc_inprogress(struct phl_info_t *phl, u8 band_idx)
{
	bool ret = false;
	struct phl_mcc_info *minfo = NULL;

	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_inprogress(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, band_idx);
	if (MCC_TRIGGER_FW_EN == minfo->state || MCC_RUNING == minfo->state ||
		MCC_TRIGGER_FW_DIS == minfo->state ||
		MCC_FW_DIS_FAIL == minfo->state) {
		ret = true;
	}
exit:
	return ret;
}

/* Enable Fw MCC
 * @cur_role: the role in the current ch.
 */
enum rtw_phl_status rtw_phl_mcc_enable(struct phl_info_t *phl,
					struct rtw_wifi_role_t *cur_role)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, cur_role->hw_band);
	u8 role_map = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_enable(): cur_role->type(%d)\n",
		cur_role->type);
	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, cur_role->hw_band);
	en_info = &minfo->en_info;
	if (MCC_NONE != minfo->state && MCC_STOP != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): (MCC_NONE != minfo->state || MCC_STOP != minfo->state(%d)), please check code flow\n",
			minfo->state);
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	_mcc_set_state(minfo, MCC_CFG_EN_INFO);
	if (RTW_PHL_STATUS_SUCCESS != _mcc_get_role_map(phl, band_ctrl,
							&role_map)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): Get role map failed\n");
		goto _cfg_info_fail;
	}
	_mcc_reset_minfo(phl, minfo, (MINFO_RESET_EN_INFO | MINFO_RESET_MODE |
				MINFO_RESET_ROLE_MAP | MINFO_RESET_COEX_MODE |
				MINFO_RESET_BT_INFO));
	minfo->role_map = role_map;
	if (RTW_PHL_STATUS_SUCCESS != _mcc_transfer_mode(phl, minfo,
							role_map)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): transfer mcc mode failed\n");
		goto _cfg_info_fail;
	}
	if (RTW_PHL_STATUS_SUCCESS != _mcc_fill_role_info(phl, en_info,
							role_map, cur_role)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): fill role info failed\n");
		goto _cfg_info_fail;
	}
	_mcc_fill_coex_mode(phl, minfo);
	_mcc_fill_bt_dur(phl, minfo);
	if (RTW_PHL_STATUS_SUCCESS != _mcc_get_mrole_idx_by_wrole(minfo,
					cur_role, &en_info->ref_role_idx)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): fill ref_role idx failed\n");
		goto _cfg_info_fail;
	}
	if (minfo->mcc_mode == RTW_PHL_TDMRA_AP_CLIENT_WMODE) {
		if (RTW_PHL_STATUS_SUCCESS !=
			_mcc_fill_info_for_ap_client_mode(phl, minfo)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): fill info failed for ap_client mode\n");
			goto _cfg_info_fail;
		}
	} else if (minfo->mcc_mode == RTW_PHL_TDMRA_2CLIENTS_WMODE){
		if (RTW_PHL_STATUS_SUCCESS !=
			_mcc_fill_info_for_2_clients_mode(phl, minfo)) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): fill info failed for 2clients mode\n");
			goto _cfg_info_fail;
		}
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): Undefined mcc_mode(%d)\n",
			minfo->mcc_mode);
		goto _cfg_info_fail;
	}
	_mcc_dump_mcc_info(minfo);
	if (RTW_PHL_STATUS_SUCCESS != _mcc_pkt_offload(phl, en_info)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): pkt offload Fail\n");
		goto _cfg_info_fail;
	}
	_mcc_set_state(minfo, MCC_TRIGGER_FW_EN);
	if (rtw_hal_mcc_enable(phl->hal, en_info, &minfo->bt_info) !=
						RTW_HAL_STATUS_SUCCESS) {
		_mcc_set_state(minfo, MCC_FW_EN_FAIL);
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_enable(): Enable FW mcc Fail\n");
		goto exit;
	}
	_mcc_set_state(minfo, MCC_RUNING);
	PHL_TRACE(COMP_PHL_MCC, _PHL_ALWAYS_, "rtw_phl_mcc_enable(): Enable FW mcc ok\n");
	if (minfo->mcc_mode == RTW_PHL_TDMRA_AP_CLIENT_WMODE)
		_mcc_up_noa(phl, minfo);
	_mcc_dump_mcc_info(minfo);
	_mcc_up_fw_log_setting(phl, minfo);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
_cfg_info_fail:
	_mcc_set_state(minfo, MCC_NONE);
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "<<< rtw_phl_mcc_enable():status(%d)\n",
		status);
	return status;
}

/*
 * Stop fw mcc
 * @ spec_role: You want to fw switch ch to the specific ch of the role when fw stop mcc
 */
enum rtw_phl_status rtw_phl_mcc_disable(struct phl_info_t *phl,
					struct rtw_wifi_role_t *spec_role)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct rtw_phl_mcc_role *m_role = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_disable()\n");
	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_disable(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, spec_role->hw_band);
	en_info = &minfo->en_info;
	if (MCC_RUNING != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_disable(): MCC_RUNING != m_info->state, please check code flow\n");
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	if (NULL == (m_role = _mcc_get_mrole_by_wrole(minfo, spec_role))) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_disable(): Can't get mrole, wrole id(%d), please check code flow\n",
			spec_role->id);
		goto exit;
	}
	_mcc_set_state(minfo, MCC_TRIGGER_FW_DIS);
	if (rtw_hal_mcc_disable(phl->hal, m_role->group, m_role->macid)
						!= RTW_HAL_STATUS_SUCCESS) {
		status = RTW_PHL_STATUS_FAILURE;
		_mcc_set_state(minfo, MCC_FW_DIS_FAIL);
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_,"rtw_phl_mcc_disable(): Disable FW mcc Fail\n");
		goto exit;
	}
	rtw_hal_sync_cur_ch(phl->hal, spec_role->hw_band, spec_role->chandef);
	_mcc_set_state(minfo, MCC_STOP);
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_disable(): Disable FW mcc ok\n");
	if (minfo->mcc_mode == RTW_PHL_TDMRA_AP_CLIENT_WMODE)
		_mcc_clean_noa(phl, en_info);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}


enum rtw_phl_status rtw_phl_tdmra_duration_change(struct phl_info_t *phl,
			struct phl_tdmra_dur_change_info *info)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_en_info *en_info = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_tdmra_duration_change()\n");
	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_duration_change(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, info->hw_band);
	en_info = &minfo->en_info;
	if (MCC_RUNING != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_duration_change(): MCC_RUNING != m_info->state, please check code flow\n");
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	if (true == info->bt_role) {
		status = rtw_phl_mcc_bt_duration_change(phl, info);
	} else {
		status = rtw_phl_mcc_duration_change(phl, info);
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< rtw_phl_tdmra_duration_change(): status(%d)\n",
		status);
exit:
	return status;
}

enum rtw_phl_status rtw_phl_tdmra_enable(struct phl_info_t *phl,
				struct rtw_wifi_role_t *cur_role)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, cur_role->hw_band);
	struct mr_info *cur_info = &band_ctrl->cur_info;
	u8 chanctx_num = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_tdmra_enable\n");
	chanctx_num = (u8)phl_mr_get_chanctx_num(phl, band_ctrl);
	if (2 == chanctx_num) {
		status = rtw_phl_mcc_enable(phl, cur_role);
	} else if (1 == chanctx_num) {
		if ((1 == cur_info->ap_num || 1 == cur_info->p2p_go_num) &&
		   (cur_info->ld_sta_num == 0 || cur_info->lg_sta_num == 0)) {
			status = rtw_phl_mcc_ap_bt_coex_enable(phl, cur_role);
		} else {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_enable(): Not support this type\n");
			PHL_DUMP_MR_EX(phl);
		}
	} else {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_enable(): Not support for chanctx_num(%d)\n",
			chanctx_num);
	}
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< rtw_phl_tdmra_enable(): status(%d)\n",
		status);
	return status;
}

/*
 * Stop tdmra
 * @ spec_role: You want to fw switch ch to the specific ch of the role when fw stop tdma
 */
enum rtw_phl_status rtw_phl_tdmra_disable(struct phl_info_t *phl,
				struct rtw_wifi_role_t *spec_role)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_en_info *en_info = NULL;
	struct rtw_phl_mcc_role *m_role = NULL;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_tdmra_disable()\n");
	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_disable(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, spec_role->hw_band);
	en_info = &minfo->en_info;
	if (MCC_RUNING != minfo->state) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_disable(): MCC_RUNING != m_info->state, please check code flow\n");
		_mcc_dump_state(&minfo->state);
		goto exit;
	}
	if (NULL == (m_role = _mcc_get_mrole_by_wrole(minfo, spec_role))) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_disable(): Can't get mrole, wrole id(%d), please check code flow\n",
			spec_role->id);
		#ifdef RTW_WKARD_TDMRA_AUTO_GET_STAY_ROLE
		m_role = get_ref_role(en_info);
		if (m_role == NULL) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s(): Can't get mrole from ref_mrole, please check code flow\n",
				__func__);
			goto exit;
		} else {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s(): Workaround get mrore from ref_mrole\n",
				__func__);
		}
		#else
		goto exit;
		#endif /* RTW_WKARD_TDMRA_AUTO_GET_STAY_ROLE */
	}
	_mcc_set_state(minfo, MCC_TRIGGER_FW_DIS);
	if (rtw_hal_mcc_disable(phl->hal, m_role->group, m_role->macid)
						!= RTW_HAL_STATUS_SUCCESS) {
		status = RTW_PHL_STATUS_FAILURE;
		_mcc_set_state(minfo, MCC_FW_DIS_FAIL);
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_,"rtw_phl_tdmra_disable(): Disable FW mcc Fail\n");
		goto exit;
	}
	rtw_hal_sync_cur_ch(phl->hal, m_role->wrole->hw_band, *m_role->chandef);
	_mcc_set_state(minfo, MCC_STOP);
	PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_tdmra_disable(): Disable FW mcc ok\n");
	if (minfo->mcc_mode == RTW_PHL_TDMRA_AP_CLIENT_WMODE ||
		minfo->mcc_mode == RTW_PHL_TDMRA_AP_WMODE)
		_mcc_clean_noa(phl, en_info);
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< rtw_phl_tdmra_disable(): status(%d)\n",
		status);
	return status;
}

enum rtw_phl_status rtw_phl_mcc_init_ops(struct phl_info_t *phl, struct rtw_phl_mcc_ops *ops)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct phl_com_mcc_info *com_info = NULL;

	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_init_ops(): mcc is not init, please check code\n");
		goto exit;
	}
	com_info = phl_to_com_mcc_info(phl);
	com_info->ops.priv = ops->priv;
	com_info->ops.mcc_update_noa = ops->mcc_update_noa;
	com_info->ops.mcc_get_setting = ops->mcc_get_setting;
	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_phl_mcc_init_ops(): init ok\n");
	status = RTW_PHL_STATUS_SUCCESS;
exit:
	return status;
}

enum rtw_phl_status rtw_phl_mcc_init(struct phl_info_t *phl)
{
	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
	struct rtw_phl_com_t *phl_com = phl->phl_com;
	void *drv = phl_to_drvpriv(phl);
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = NULL;
	u8 band_idx = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_init()\n");
	set_mcc_init_state(phl, false);
	if (mr_ctl->com_mcc == NULL) {
		mr_ctl->com_mcc = _os_mem_alloc(drv, sizeof(struct phl_com_mcc_info));
		if (mr_ctl->com_mcc != NULL) {
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_phl_mcc_init(): Allocate phl_com_mcc_info\n");
		} else {
			PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_init(): Allocate phl_com_mcc_info Fail\n");
			goto deinit;
		}
	}
	for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
		band_ctrl = &mr_ctl->band_ctrl[band_idx];
		if (band_ctrl->mcc_info == NULL) {
			band_ctrl->mcc_info = _os_mem_alloc(drv,
						sizeof(struct phl_mcc_info));
			if (band_ctrl->mcc_info != NULL) {
				PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_phl_mcc_init(): Allocate mcc_info for HW Band(%d)\n",
					band_idx);
			} else {
				PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_init(): Allocate mcc_info fail for HW Band(%d)\n",
					band_idx);
				goto deinit;
			}
		}
	}
	set_mcc_init_state(phl, true);
	status = RTW_PHL_STATUS_SUCCESS;
	goto exit;
deinit:
	rtw_phl_mcc_deinit(phl);
exit:
	return status;
}

void rtw_phl_mcc_deinit(struct phl_info_t *phl)
{
	struct rtw_phl_com_t *phl_com = phl->phl_com;
	void *drv = phl_to_drvpriv(phl);
	struct phl_com_mcc_info *com_info = phl_to_com_mcc_info(phl);
	struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
	struct hw_band_ctl_t *band_ctrl = NULL;
	u8 band_idx = 0;

	PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> rtw_phl_mcc_deinit()\n");
	if (com_info != NULL) {
		_os_mem_free(drv, com_info, sizeof(struct phl_com_mcc_info));
		PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_phl_mcc_deinit(): Free phl_com_mcc_info\n");
	}
	for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
		band_ctrl = &mr_ctl->band_ctrl[band_idx];
		if (band_ctrl->mcc_info != NULL) {
			_os_mem_free(drv, band_ctrl->mcc_info,
						sizeof(struct phl_mcc_info));
			PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_phl_mcc_deinit(): Free phl_mcc_info, HwBand(%d)\n",
				band_idx);
		}
	}
	set_mcc_init_state(phl, false);
}

bool rtw_phl_mcc_get_dbg_info(struct phl_info_t *phl, u8 band_idx,
				enum rtw_phl_mcc_dbg_type type, void *info)
{
	bool get_ok = false;
	struct phl_mcc_info *minfo = NULL;
	struct rtw_phl_mcc_en_info *en_info = NULL;

	if (!is_mcc_init(phl)) {
		PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_get_dbg_info(): mcc is not init, please check code\n");
		goto exit;
	}
	minfo = get_mcc_info(phl, band_idx);
	en_info = &minfo->en_info;

	if (MCC_DBG_STATE == type) {
		*(enum rtw_phl_mcc_state *)info = minfo->state;
	} else if (MCC_DBG_OP_MODE == type) {
		*(enum rtw_phl_tdmra_wmode *)info = minfo->mcc_mode;
	} else if (MCC_DBG_COEX_MODE == type) {
		*(enum rtw_phl_mcc_coex_mode *)info = minfo->coex_mode;
	} else if (MCC_DBG_BT_INFO == type) {
		_os_mem_cpy(phl_to_drvpriv(phl), info, &minfo->bt_info,
				sizeof(struct rtw_phl_mcc_bt_info));
	} else if (MCC_DBG_EN_INFO == type) {
		_os_mem_cpy(phl_to_drvpriv(phl), info, en_info,
				sizeof(struct rtw_phl_mcc_en_info));
	} else {
		goto exit;
	}
	get_ok = true;

exit:
	return get_ok;
}


#endif /* CONFIG_MCC_SUPPORT */
