android13/external/wifi_driver/rtl8852be/phl/phl_mcc.c

3956 lines
146 KiB
C

/******************************************************************************
*
* 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 = rtw_phl_get_wrole_by_ridx(phl->phl_com, 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 = rtw_phl_get_wrole_by_ridx(phl->phl_com, 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,
minfo->mcc_mode) != 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,
minfo->mcc_mode) != 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;
}
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_notify_mcc_macid(phl->hal,
mrole,
minfo->mcc_mode)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_sta_entry_change(): Notify macid map fail\n");
}
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;
}
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_notify_mcc_macid(phl->hal,
mrole,
minfo->mcc_mode)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_phl_mcc_client_link_notify_for_ap(): Notify macid map fail\n");
}
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;
}
static bool _is_mcc_sts_err(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_,
"%s(): mcc is not init, please check code\n",
__func__);
goto exit;
}
minfo = get_mcc_info(phl, band_idx);
if (MCC_FW_DIS_FAIL == minfo->state ||
MCC_FW_EN_FAIL == minfo->state) {
ret = true;
}
exit:
return ret;
}
enum rtw_phl_status rtw_phl_mcc_reset(struct phl_info_t *phl,
u8 band_idx)
{
enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
struct rtw_phl_mcc_en_info *en_info = NULL;
struct phl_mcc_info *minfo = NULL;
FUNCIN();
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, band_idx);
en_info = &minfo->en_info;
/* Reset mcc */
rtw_hal_mcc_reset(phl->hal, en_info->group, minfo->mcc_mode);
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_,
"%s(): reset mcc group(%d) complete\n",
__func__, en_info->group);
/* Reset state */
_mcc_set_state(minfo, MCC_NONE);
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:
return status;
}
enum rtw_phl_status rtw_phl_mcc_recovery(struct phl_info_t *phl,
u8 band_idx)
{
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
if (_is_mcc_sts_err(phl, band_idx)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_,
"%s: err status detected, try to reset mcc.\n",
__func__);
rtw_phl_mcc_reset(phl, band_idx);
}
return status;
}
/* 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,
minfo->mcc_mode) != 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,
minfo->mcc_mode) != 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,
minfo->mcc_mode) != 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 */