2025-05-10 21:58:58 +08:00

443 lines
14 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 _HAL_MCC_C_
#include "hal_headers.h"
#include "hal_mcc.h"
#ifdef CONFIG_MCC_SUPPORT
#define _mcc_fill_slot_bt_coex(_dbg_hal_i, _en) ((struct rtw_phl_mcc_dbg_hal_info *)_dbg_hal_i)->btc_in_group = _en;
void _mcc_update_slot_dbg_info(struct rtw_phl_mcc_dbg_hal_info *dbg_hal_i,
bool bt_role, u16 macid, u16 dur)
{
struct rtw_phl_mcc_dbg_slot_info *dbg_slot_i = NULL;
u8 idx = 0;
for (idx = 0; idx < dbg_hal_i->slot_num; idx++) {
dbg_slot_i = &dbg_hal_i->dbg_slot_i[idx];
if (dbg_slot_i->bt_role) {
if (bt_role) {
dbg_slot_i->dur = dur;
break;
}
} else if (false == bt_role && dbg_slot_i->macid == macid) {
dbg_slot_i->dur = dur;
break;
}
}
}
void _mcc_update_dbg_info(struct rtw_phl_mcc_en_info *info,
struct rtw_phl_mcc_bt_info *bt_info)
{
u8 idx = 0;
if (bt_info->bt_dur > 0) {
_mcc_fill_slot_bt_coex(&info->dbg_hal_i, true);
} else {
_mcc_fill_slot_bt_coex(&info->dbg_hal_i, false);
}
for (idx = 0; idx < info->mrole_num; idx++) {
_mcc_update_slot_dbg_info(&info->dbg_hal_i, false,
info->mcc_role[idx].macid,
info->mcc_role[idx].policy.dur_info.dur);
}
}
void _mcc_fill_slot_dbg_info(struct rtw_phl_mcc_dbg_hal_info *dbg_hal_i,
struct rtw_phl_mcc_role *mrole)
{
struct rtw_phl_mcc_dbg_slot_info *dbg_slot_i = NULL;
if (dbg_hal_i->slot_num >= SLOT_NUM) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_hal_dbg_info(): Fill fail, dbg_hal_i->slot_num(%d) >= SLOT_NUM(%d), please check code\n",
dbg_hal_i->slot_num, SLOT_NUM);
goto exit;
}
dbg_slot_i = &dbg_hal_i->dbg_slot_i[dbg_hal_i->slot_num];
dbg_slot_i->bt_role = mrole->bt_role ? true : false;
dbg_slot_i->dur = mrole->policy.dur_info.dur;
if (false == dbg_slot_i->bt_role) {
dbg_slot_i->ch = mrole->chandef->chan;
dbg_slot_i->macid = mrole->macid;
}
dbg_hal_i->slot_num++;
exit:
return;
}
enum rtw_hal_status _mcc_add_bt_role(struct hal_info_t *hal, u8 group,
struct rtw_phl_mcc_slot_info *slot_i,
struct rtw_phl_mcc_dbg_hal_info *dbg_hal_i)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
struct rtw_phl_mcc_role mrole = {0};
mrole.policy.dur_info.dur = (u8)slot_i->slot;
mrole.bt_role = true;
mrole.group = group;
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_add_bt_role(): add bt role\n");
_mcc_fill_slot_dbg_info(dbg_hal_i, &mrole);
status = rtw_hal_mac_add_mcc(hal, &mrole);
return status;
}
enum rtw_hal_status _mcc_add_wifi_role(struct hal_info_t *hal,
u8 group, struct rtw_phl_mcc_slot_info *slot_i,
struct rtw_phl_mcc_dbg_hal_info *dbg_hal_i)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
struct rtw_phl_mcc_role *mrole = slot_i->mrole;
if (NULL == mrole) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_add_wifi_role(): Fail, NULL == mrole, Please check code\n");
goto exit;
}
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_add_wifi_role(): add wifi role\n");
mrole->group = group;
_mcc_fill_slot_dbg_info(dbg_hal_i, mrole);
status = rtw_hal_mac_add_mcc(hal, mrole);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_add_wifi_role(): Add mcc failed\n");
goto exit;
}
status = rtw_hal_mcc_update_macid_bitmap(hal, group,
(u8)mrole->macid,
&mrole->used_macid);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_add_wifi_role(): Add MACID bitmap failed\n");
goto exit;
}
exit:
return status;
}
enum rtw_hal_status _mcc_fill_role_setting(struct hal_info_t *hal,
struct rtw_phl_mcc_en_info *info)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
struct rtw_phl_mcc_slot_info *slot_i = info->m_pattern.slot_order;
u8 i = 0;
if (info->m_pattern.slot_num > SLOT_NUM) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_setting(): Fial, slot_num(%d) > SLOT_NUM(%d), please check code\n",
info->m_pattern.slot_num, SLOT_NUM);
goto exit;
} else if (info->m_pattern.slot_num < MIN_TDMRA_SLOT_NUM) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_setting(): Fial, slot_num(%d) < MIN_TDMRA_SLOT_NUM(%d), please check code\n",
info->m_pattern.slot_num, MIN_TDMRA_SLOT_NUM);
goto exit;
}
for (i = 0; i < info->m_pattern.slot_num; i++) {
if (!slot_i[i].bt_role) {
if (RTW_HAL_STATUS_SUCCESS!= _mcc_add_wifi_role(hal,
info->group, &slot_i[i], &info->dbg_hal_i)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_setting(): Add wifi role failed\n");
goto exit;
}
} else {
if (RTW_HAL_STATUS_SUCCESS != _mcc_add_bt_role(hal,
info->group, &slot_i[i], &info->dbg_hal_i)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_fill_role_setting(): Add bt role failed\n");
goto exit;
}
}
}
status = RTW_HAL_STATUS_SUCCESS;
exit:
return status;
}
enum rtw_hal_status _mcc_replace_pattern(struct hal_info_t *hal,
struct rtw_phl_mcc_en_info *ori_info,
struct rtw_phl_mcc_en_info *new_info,
struct rtw_phl_mcc_bt_info *new_bt_info)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
struct rtw_phl_mcc_role *ref_role =
&new_info->mcc_role[new_info->ref_role_idx];
bool btc_in_group = false;
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, ">>> _mcc_replace_pattern\n");
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mac_get_mcc_group(hal, &new_info->group)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_replace_pattern(): Allocate group fail\n");
goto exit;
}
_os_mem_set(hal_to_drvpriv(hal), &new_info->dbg_hal_i, 0,
sizeof(struct rtw_phl_mcc_dbg_hal_info));
status = _mcc_fill_role_setting(hal, new_info);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_replace_pattern(): Fail fill role setting\n");
goto exit;
}
if (new_info->sync_tsf_info.sync_en) {
status = rtw_hal_mcc_sync_enable(hal, new_info);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_replace_pattern(): Sync enable failed\n");
goto exit;
}
}
if (new_bt_info->bt_dur > 0) {
btc_in_group = true;
_mcc_fill_slot_bt_coex(&new_info->dbg_hal_i, true);
} else {
_mcc_fill_slot_bt_coex(&new_info->dbg_hal_i, false);
}
status = rtw_hal_mac_start_mcc(hal, new_info->group,
(u8)ref_role->macid, new_info->tsf_high,
new_info->tsf_low, btc_in_group, 1, ori_info->group);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_replace_pattern(): Start MCC failed\n");
goto exit;
}
status = RTW_HAL_STATUS_SUCCESS;
exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "<<< _mcc_replace_pattern(): Ststus(%d)\n",
status);
return status;
}
enum rtw_hal_status rtw_hal_mcc_get_2ports_tsf(void *hal, u8 group,
u16 macid_x, u16 macid_y, u32 *tsf_x_h, u32 *tsf_x_l,
u32 *tsf_y_h, u32 *tsf_y_l)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
status = rtw_hal_mac_mcc_request_tsf(hal, group, (u8)macid_x, (u8)macid_y);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_get_2ports_tsf(): Req tsf failed\n");
goto exit;
}
status = rtw_hal_mac_get_mcc_tsf_rpt(hal, group, tsf_x_h, tsf_x_l,
tsf_y_h, tsf_y_l);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_get_2ports_tsf(): Get tsf rpt failed\n");
goto exit;
}
exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_hal_mcc_get_2ports_tsf(): Ststus(%d)\n",
status);
return status;
}
enum rtw_hal_status rtw_hal_notify_mcc_macid(void *hal,
struct rtw_phl_mcc_role *mrole,
enum rtw_phl_tdmra_wmode wmode)
{
enum rtw_hal_status sts = RTW_HAL_STATUS_FAILURE;
if (wmode == RTW_PHL_TDMRA_AP_CLIENT_WMODE ||
wmode == RTW_PHL_TDMRA_2CLIENTS_WMODE) {
if (sts != rtw_hal_bb_upd_mcc_macid(hal, mrole)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "%s: Notify BB MCC MACID bitmap failed\n",
__FUNCTION__);
goto exit;
}
}
sts = RTW_HAL_STATUS_SUCCESS;
exit:
return sts;
}
enum rtw_hal_status rtw_hal_mcc_update_macid_bitmap(void *hal, u8 group,
u16 macid, struct rtw_phl_mcc_macid_bitmap *info)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
status = rtw_hal_mac_mcc_macid_bitmap(hal, group, (u8)macid,
(u8 *)info->bitmap, info->len);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_update_macid_bitmap(): Add MACID bitmap failed\n");
}
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_hal_mcc_update_macid_bitmap(): Ststus(%d)\n",
status);
return status;
}
enum rtw_hal_status rtw_hal_mcc_sync_enable(void *hal,
struct rtw_phl_mcc_en_info *info)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
struct rtw_phl_mcc_role *ref_role = &info->mcc_role[info->ref_role_idx];
if (info->sync_tsf_info.sync_en) {
status = rtw_hal_mac_mcc_sync_enable(hal, ref_role->group,
(u8)info->sync_tsf_info.source,
(u8)info->sync_tsf_info.target,
(u8)info->sync_tsf_info.offset);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_sync_enable(): Sync enable failed\n");
goto exit;
}
} else {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_sync_enable(): sync_en == false, please check code\n");
goto exit;
}
status = RTW_HAL_STATUS_SUCCESS;
exit:
return status;
}
enum rtw_hal_status _mcc_set_duration(void *hal,
struct rtw_phl_mcc_en_info *info,
struct rtw_phl_mcc_bt_info *bt_info)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
status = rtw_hal_mac_set_duration(hal, info, bt_info);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "_mcc_set_duration(): set duration failed\n");
} else {
_mcc_update_dbg_info(info, bt_info);
}
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "_mcc_set_duration(): Ststus(%d)\n",
status);
return status;
}
enum rtw_hal_status rtw_hal_mcc_change_pattern(void *hal,
struct rtw_phl_mcc_en_info *ori_info,
struct rtw_phl_mcc_en_info *new_info,
struct rtw_phl_mcc_bt_info *new_bt_info)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
/* mcc_set_duration only can change 2 wifi slot,
otherwise we shall create new pattern and replace previous pattern*/
if (new_info->m_pattern.slot_num == 2 &&
new_info->m_pattern.bt_slot_num == 0 &&
ori_info->m_pattern.slot_num == 2 &&
ori_info->m_pattern.bt_slot_num == 0) {
status = _mcc_set_duration(hal, new_info, new_bt_info);
} else {
status = _mcc_replace_pattern(hal, ori_info, new_info,
new_bt_info);
}
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_hal_mcc_change_pattern(): status(%d)\n",
status);
return status;
}
enum rtw_hal_status rtw_hal_mcc_reset(void *hal, u8 group,
enum rtw_phl_tdmra_wmode wmode)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
status = rtw_hal_mac_reset_mcc_group(hal, group);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_,
"%s(): reset group(%d) failed\n",
__func__, group);
goto exit;
}
if (wmode == RTW_PHL_TDMRA_AP_CLIENT_WMODE ||
wmode == RTW_PHL_TDMRA_2CLIENTS_WMODE) {
rtw_hal_bb_mcc_stop(hal);
}
status = RTW_HAL_STATUS_SUCCESS;
exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s(): status(%d)\n",
__func__, status);
return status;
}
enum rtw_hal_status rtw_hal_mcc_disable(void *hal, u8 group, u16 macid,
enum rtw_phl_tdmra_wmode wmode)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
status = rtw_hal_mac_stop_mcc(hal, group, (u8)macid);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_disable(): Stop mcc failed\n");
goto exit;
}
status = rtw_hal_mac_del_mcc_group(hal, group);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_disable(): Delete group failed\n");
goto exit;
}
if (wmode == RTW_PHL_TDMRA_AP_CLIENT_WMODE ||
wmode == RTW_PHL_TDMRA_2CLIENTS_WMODE) {
rtw_hal_bb_mcc_stop(hal);
}
#ifdef RTW_WKARD_HALRF_MCC
rtw_hal_rf_dpk_switch(hal, true);
#endif /* RTW_WKARD_HALRF_MCC */
status = RTW_HAL_STATUS_SUCCESS;
exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_hal_mcc_disable(): Ststus(%d)\n",
status);
return status;
}
enum rtw_hal_status rtw_hal_mcc_enable(void *hal, struct rtw_phl_mcc_en_info *info,
struct rtw_phl_mcc_bt_info *bt_info,
enum rtw_phl_tdmra_wmode wmode)
{
enum rtw_hal_status status = RTW_HAL_STATUS_FAILURE;
struct rtw_phl_mcc_role *ref_role = &info->mcc_role[info->ref_role_idx];
bool btc_in_group = false;
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_mac_get_mcc_group(hal, &info->group)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_enable(): Allocate group fail\n");
goto exit;
}
#ifdef RTW_WKARD_HALRF_MCC
rtw_hal_rf_dpk_switch(hal, false);
#endif /* RTW_WKARD_HALRF_MCC */
if (RTW_HAL_STATUS_SUCCESS != _mcc_fill_role_setting(hal, info)) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_enable(): Fail fill role setting\n");
goto exit;
}
/*fill start setting*/
if (info->sync_tsf_info.sync_en) {
status = rtw_hal_mcc_sync_enable(hal, info);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_enable(): Sync enable failed\n");
goto exit;
}
}
if (bt_info->bt_dur > 0) {
btc_in_group = true;
_mcc_fill_slot_bt_coex(&info->dbg_hal_i, true);
} else {
_mcc_fill_slot_bt_coex(&info->dbg_hal_i, false);
}
status = rtw_hal_mac_start_mcc(hal, info->group,
(u8)ref_role->macid, info->tsf_high,
info->tsf_low, btc_in_group, 0, 0);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_enable(): Start MCC failed\n");
goto exit;
}
if (wmode == RTW_PHL_TDMRA_AP_CLIENT_WMODE ||
wmode == RTW_PHL_TDMRA_2CLIENTS_WMODE) {
status = rtw_hal_bb_mcc_start(hal, &info->mcc_role[0],
&info->mcc_role[1]);
if (status != RTW_HAL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_MCC, _PHL_ERR_, "rtw_hal_mcc_enable(): Notify MCC start failed\n");
}
}
status = RTW_HAL_STATUS_SUCCESS;
exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "rtw_hal_mcc_enable(): Ststus(%d)\n",
status);
return status;
}
#endif /* CONFIG_MCC_SUPPORT */