Files
linux-nv-oot/drivers/net/wireless/realtek/rtl8852ce/phl/phl_mr.c
Shobek Attupurath 04fa635c7d rtl8852ce: Add Nvidia changes to v1.19.16.1-0-g1fe335ba1.20240815_PC
1. Update makefiles to add Nvidia source path
2. Change file permissions to 0644
3. Delete files with .orig extensions
4. Fix compilation issue due to enum-int mismatch

Bug 4667769
Bug 4667981

Change-Id: I0df6f3073780daf6879c4165cd97fd62fd0a4b65
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3195602
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>
Tested-by: Shobek Attupurath <sattupurath@nvidia.com>
2025-07-24 10:19:09 +00:00

4628 lines
135 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_MR_C_
#include "phl_headers.h"
#ifdef DBG_PHL_MR
void phl_mr_dump_role_info(const char *caller, const int line, bool show_caller,
struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole)
{
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
if (show_caller)
PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);
PHL_INFO("\t[WROLE] RIDX:%d - MAC-Addr:%02x-%02x-%02x-%02x-%02x-%02x RTYPE:%d MSTS:%d\n",
wrole->id, wrole->mac_addr[0], wrole->mac_addr[1], wrole->mac_addr[2],
wrole->mac_addr[3], wrole->mac_addr[4], wrole->mac_addr[5],
wrole->type, wrole->mstate);
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
PHL_INFO("\t[WROLE LINK] HW Band_idx:%d, Port_idx:%d, WMM_idx:%d\n", rlink->hw_band, rlink->hw_port, rlink->hw_wmm);
if (rtw_phl_role_is_ap_category(wrole) || wrole->type == PHL_RTYPE_MESH) {
#ifdef RTW_PHL_BCN
PHL_INFO("\t[WROLE AP] BSSID:%02x-%02x-%02x-%02x-%02x-%02x\n",
rlink->bcn_cmn.bssid[0], rlink->bcn_cmn.bssid[1], rlink->bcn_cmn.bssid[2],
rlink->bcn_cmn.bssid[3], rlink->bcn_cmn.bssid[4], rlink->bcn_cmn.bssid[5]);
PHL_INFO("\t[WROLE AP] BCN id:%d, interval:%d, rate:0x%04x, DTIM:%d\n",
rlink->bcn_cmn.bcn_id, rlink->bcn_cmn.bcn_interval,
rlink->bcn_cmn.bcn_rate, rlink->bcn_cmn.bcn_dtim);
PHL_INFO("\t[WROLE AP] HW MBSSID idx:%d, MBID NUM:%d\n",
rlink->hw_mbssid, rlink->mbid_num);
#endif
}
}
PHL_INFO("\n");
if (show_caller)
PHL_INFO("#################################\n");
}
void phl_mr_dump_rlink_info(const char *caller, const int line, bool show_caller,
struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink)
{
if (show_caller)
PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);
PHL_INFO("\t[RLINK] LIDX:%d - MAC-Addr:%02x-%02x-%02x-%02x-%02x-%02x RTYPE:%d MSTS:%d\n",
rlink->id,
rlink->mac_addr[0], rlink->mac_addr[1], rlink->mac_addr[2],
rlink->mac_addr[3], rlink->mac_addr[4], rlink->mac_addr[5],
wrole->type, rlink->mstate);
PHL_INFO("\t[RLINK] HW Band_idx:%d, Port_idx:%d, WMM_idx:%d\n",
rlink->hw_band, rlink->hw_port, rlink->hw_wmm);
if (rtw_phl_role_is_ap_category(wrole) || wrole->type == PHL_RTYPE_MESH) {
#ifdef RTW_PHL_BCN
PHL_INFO("\t[RLINK AP] BSSID:%02x-%02x-%02x-%02x-%02x-%02x\n",
rlink->bcn_cmn.bssid[0], rlink->bcn_cmn.bssid[1],
rlink->bcn_cmn.bssid[2], rlink->bcn_cmn.bssid[3],
rlink->bcn_cmn.bssid[4], rlink->bcn_cmn.bssid[5]);
PHL_INFO("\t[RLINK AP] BCN id:%d, interval:%d, rate:0x%04x, DTIM:%d\n",
rlink->bcn_cmn.bcn_id, rlink->bcn_cmn.bcn_interval,
rlink->bcn_cmn.bcn_rate, rlink->bcn_cmn.bcn_dtim);
PHL_INFO("\t[RLINK AP] HW MBSSID idx:%d, MBID NUM:%d\n",
rlink->hw_mbssid, rlink->mbid_num);
#endif
}
PHL_INFO("\n");
if (show_caller)
PHL_INFO("#################################\n");
}
void phl_mr_dump_chctx_info(const char *caller, const int line, bool show_caller,
struct phl_info_t *phl_info, struct phl_queue *chan_ctx_queue, struct rtw_chan_ctx *chanctx)
{
u8 role_num = 0;
role_num = phl_chanctx_get_rnum(phl_info, chan_ctx_queue, chanctx);
if (show_caller)
PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);
PHL_INFO("\t[CH-CTX] role num:%d map:0x%02x, DFS enable:%s\n",
role_num, chanctx->role_map,
(chanctx->dfs_enabled) ? "Y" : "N");
PHL_DUMP_CHAN_DEF(&chanctx->chan_def);
if (show_caller)
PHL_INFO("#################################\n");
}
const char *const _opmod_str[] = {
"MR_OP_NONE",
"MR_OP_SWR",
"MR_OP_SCC",
"MR_OP_MCC",
"MR_OP_DBCC",
"MR_OP_NON"
};
#define _get_opmod_str(opmod) (((opmod) >= MR_OP_MAX) ? _opmod_str[MR_OP_MAX] : _opmod_str[(opmod)])
void phl_dump_cc_band_map(struct phl_info_t *phl_info, u16 cc_band_map)
{
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\t chctx_band -");
if (cc_band_map == 0)
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_NON");
if (cc_band_map & BIT(CC_BAND_24G))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_24G");
if (cc_band_map & BIT(CC_BAND_5G_B1))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B1");
if (cc_band_map & BIT(CC_BAND_5G_B2))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B2");
if (cc_band_map & BIT(CC_BAND_5G_B3))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B3");
if (cc_band_map & BIT(CC_BAND_5G_B4))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_5G_B4");
if (cc_band_map & BIT(CC_BAND_6G_U5))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U5");
if (cc_band_map & BIT(CC_BAND_6G_U6))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U6");
if (cc_band_map & BIT(CC_BAND_6G_U7))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U7");
if (cc_band_map & BIT(CC_BAND_6G_U8))
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, " %s ", "B_6G_U8");
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
}
void phl_mr_dump_band_info(const char *caller, const int line, bool show_caller,
struct phl_info_t *phl_info, struct hw_band_ctl_t *band_ctrl)
{
u8 role_num = 0;
int chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
role_num = phl_mr_get_role_num(phl_info, band_ctrl);
if (show_caller)
PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);
PHL_INFO("\t[BAND-%d] op_mode:%s port map:0x%02x, role num:%d map:0x%02x\n",
band_ctrl->id, _get_opmod_str(band_ctrl->op_mode),
band_ctrl->port_map, role_num, band_ctrl->role_map);
/*dump mr_info*/
PHL_INFO("\t[BAND-%d] sta_num:%d, ld_sta_num:%d, lg_sta_num:%d\n",
band_ctrl->id, band_ctrl->cur_info.sta_num,
band_ctrl->cur_info.ld_sta_num, band_ctrl->cur_info.lg_sta_num);
PHL_INFO("\t[BAND-%d] ap_num:%d, ld_ap_num:%d\n",
band_ctrl->id, band_ctrl->cur_info.ap_num, band_ctrl->cur_info.ld_ap_num);
PHL_INFO("\t[BAND-%d] chan_ctx num:%d, cc_band_map:0x%04x\n",
band_ctrl->id, chanctx_num, band_ctrl->chctx_band_map);
phl_dump_cc_band_map(phl_info, band_ctrl->chctx_band_map);
if (chanctx_num) {
struct rtw_chan_ctx *chanctx = NULL;
_os_list *chctx_list = &band_ctrl->chan_ctx_queue.queue;
void *drv = phl_to_drvpriv(phl_info);
_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
phl_list_for_loop(chanctx, struct rtw_chan_ctx, chctx_list, list) {
PHL_DUMP_CHAN_CTX(phl_info, &band_ctrl->chan_ctx_queue, chanctx);
}
_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
}
PHL_INFO("\n");
if (show_caller)
PHL_INFO("#################################\n");
}
void phl_mr_dump_info(const char *caller, const int line, bool show_caller,
struct phl_info_t *phl_info)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct rtw_wifi_role_t *wrole;
u8 i;
u8 role_num = 0;
if (show_caller)
PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);
for (i = 0; i < MAX_WIFI_ROLE_NUMBER; i++) {
if (mr_ctl->role_map & BIT(i))
role_num++;
}
PHL_INFO("[MR] MAX wrole num:%d, created num:%d map:0x%02x\n",
MAX_WIFI_ROLE_NUMBER, role_num, mr_ctl->role_map);
PHL_INFO("[MR] is_db:%s, cck_phyidx:%d\n",
(mr_ctl->is_db) ? "Y" : "N",
mr_ctl->cck_phyidx);
for (i = 0; i < MAX_WIFI_ROLE_NUMBER; i++) {
if (mr_ctl->role_map & BIT(i)) {
wrole = phl_get_wrole_by_ridx(phl_info, i);
PHL_DUMP_ROLE(phl_info, wrole);
}
}
for (i = 0; i < MAX_BAND_NUM; i++)
PHL_DUMP_BAND_CTL(phl_info, &mr_ctl->band_ctrl[i]);
if (show_caller)
PHL_INFO("#################################\n");
}
void phl_mr_dump_cur_chandef(const char *caller, const int line, bool show_caller,
struct phl_info_t *phl_info, struct rtw_wifi_role_t *wifi_role)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct rtw_chan_def *chan_def = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
if (show_caller)
PHL_INFO("###### FUN - %s LINE - %d #######\n", caller, line);
for (idx = 0; idx < wifi_role->rlink_num; idx++) {
rlink = get_rlink(wifi_role, idx);
if (rlink->chanctx) {
chan_def = &rlink->chanctx->chan_def;
PHL_INFO("==== MR Chan-def ===\n");
PHL_DUMP_CHAN_DEF(chan_def);
}
chan_def = &rlink->chandef;
PHL_INFO("==== WR-%d RLINK-%d Chan-def ===\n", wifi_role->id, rlink->id);
PHL_DUMP_CHAN_DEF(chan_def);
chan_def = &mr_ctl->hal_com->band[rlink->hw_band].cur_chandef;
PHL_INFO("==== HAL Band-%d Chan-def ===\n", rlink->hw_band);
PHL_DUMP_CHAN_DEF(chan_def);
}
if (show_caller)
PHL_INFO("#################################\n");
}
#ifdef PHL_MR_PROC_CMD
void rtw_phl_mr_dump_info(void *phl, bool show_caller)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
if (show_caller)
PHL_DUMP_MR(phl_info);
else
PHL_DUMP_MR_EX(phl_info);
}
void rtw_phl_mr_dump_band_ctl(void *phl, bool show_caller)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
int i;
for (i = 0; i < MAX_BAND_NUM; i++) {
if (show_caller)
PHL_DUMP_BAND_CTL(phl_info, &mr_ctl->band_ctrl[i]);
else
PHL_DUMP_BAND_CTL_EX(phl_info, &mr_ctl->band_ctrl[i]);
}
}
#endif /*PHL_MR_PROC_CMD*/
#endif /*DBG_PHL_MR*/
static struct rtw_wifi_role_t *_search_ld_sta_wrole(struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink,
u8 exclude_self)
{
u8 ridx = 0;
struct rtw_phl_com_t *phl_com = wrole->phl_com;
struct rtw_chan_ctx *chanctx = rlink->chanctx;
struct rtw_wifi_role_t *wr = NULL;
if (chanctx == NULL) {
PHL_ERR("%s wifi role(%d) chan ctx is null\n", __func__, wrole->id);
goto exit;
}
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (chanctx->role_map & BIT(ridx)) {
wr = &phl_com->wifi_roles[ridx];
if (wr) {
if ((exclude_self) && (wr == wrole))
continue;
if (rtw_phl_role_is_client_category(wr))
break;
}
}
}
if (wr)
PHL_INFO("search Linked STA wifi role (%d)\n", wr->id);
exit:
return wr;
}
void rtw_phl_mr_dump_cur_chandef(void *phl, struct rtw_wifi_role_t *wrole)
{
#ifdef PHL_MR_PROC_CMD
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
PHL_DUMP_CUR_CHANDEF(phl_info, wrole);
#endif
}
static enum rtw_phl_status
_phl_band_ctrl_init(struct phl_info_t *phl_info)
{
void *drv = phl_to_drvpriv(phl_info);
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
struct hw_band_ctl_t *band_ctrl;
u8 band_idx = 0;
for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
band_ctrl->id = band_idx;
_os_spinlock_init(drv, &(band_ctrl->lock));
pq_init(drv, &band_ctrl->chan_ctx_queue);
band_ctrl->op_mode = MR_OP_NONE;
band_ctrl->tsf_sync_port = HW_PORT_MAX;
band_ctrl->port_map = 0;
band_ctrl->role_map = 0;
band_ctrl->chctx_band_map = 0;
#ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP
band_ctrl->mbssid_cnt = 0;
band_ctrl->mbssid_map = 0;
#endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */
}
return RTW_PHL_STATUS_SUCCESS;
}
#ifdef RTW_WKARD_ISSUE_NULL_SLEEP_PROTECTION
#define ISSUE_NULL_TIME 50
#endif
struct mr_scan_chctx {
struct rtw_chan_def *chandef;
u8 role_map_ps;/*STA, MESH*/
u8 role_map_ap;
};
static inline enum rtw_phl_status
_phl_wr_offch_bcn_hdl(struct phl_info_t *phl_info,
u8 hw_band,
struct rtw_wifi_role_t *wr,
bool off_ch
)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
enum rtw_hal_status hsts = RTW_HAL_STATUS_SUCCESS;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
for (idx = 0; idx < wr->rlink_num; idx++) {
rlink = get_rlink(wr, idx);
if (rlink->hw_band != hw_band)
continue;
hsts = rtw_hal_beacon_stop(phl_info->hal, rlink,
RLINK_BCN_STOP_RSON_DEFAULT, off_ch);
if (hsts != RTW_HAL_STATUS_SUCCESS) {
PHL_ERR("%s %s beacon failed\n", __func__,
(off_ch) ? "stop" : "resume");
psts = RTW_PHL_STATUS_FAILURE;
}
}
return psts;
}
static inline enum rtw_phl_status
_phl_wr_offch_ps_hdl(struct phl_info_t *phl_info,
u8 hw_band,
struct rtw_wifi_role_t *wr,
bool off_ch,
void *obj_priv,
u8 module_id,
bool (*issue_null_data)(void *priv, u8 ridx, u8 lidx, bool ps,
u8 module_id))
{
enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
for (idx = 0; idx < wr->rlink_num; idx++) {
rlink = get_rlink(wr, idx);
if (rlink->hw_band != hw_band)
continue;
if (((TEST_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN)) && off_ch) ||
((!TEST_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN)) && !off_ch))
continue;
if (issue_null_data(obj_priv, wr->id, idx, off_ch, module_id)
== _SUCCESS) {
if (off_ch) {
SET_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN);
#ifdef RTW_WKARD_ISSUE_NULL_SLEEP_PROTECTION
_os_sleep_ms(phl_to_drvpriv(phl_info), ISSUE_NULL_TIME);
#endif
} else {
CLEAR_STATUS_FLAG(rlink->status, RLINK_STATUS_PS_ANN);
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s: wr(%d) rlink(%d)- hw_band(%d) off_ch(%d)\n",
__func__, wr->id, rlink->id, hw_band, off_ch);
} else {
PHL_ERR("WR-ID:%d, RLINK-ID: %d issue null_data failed\n", wr->id, idx);
_os_warn_on(1);
psts = RTW_PHL_STATUS_FAILURE;
break;
}
}
return psts;
}
#ifdef CONFIG_MR_SUPPORT
static enum rtw_phl_status
_phl_mr_offch_hdl(struct phl_info_t *phl_info,
u8 hw_band,
bool off_ch,
void *obj_priv,
u8 module_id,
bool (*issue_null_data)(void *priv, u8 ridx, u8 lidx, bool ps,
u8 module_id))
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
void *drv = phl_to_drvpriv(phl_info);
struct rtw_chan_ctx *chanctx = NULL;
struct rtw_wifi_role_t *wr = NULL;
struct mr_scan_chctx mctx = {0};
int ctx_num = 0;
u8 ridx = 0;
u8 cur_ch = rtw_hal_get_cur_ch(phl_info->hal, hw_band);
bool found = false;
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
if (issue_null_data == NULL) {
PHL_ERR("%s issue null_data function not found\n", __func__);
_os_warn_on(1);
goto _exit;
}
ctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
if (ctx_num == 0) {
PHL_DBG("ctx_num == 0!\n");
goto _exit;
}
_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {
/* Find the chanctx same as the current channel */
if(chanctx->chan_def.chan != cur_ch)
continue;
PHL_DBG("%s current chanctx found!\n", __FUNCTION__);
mctx.chandef = &chanctx->chan_def;
found = true;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (chanctx->role_map & BIT(ridx)) {
wr = &phl_com->wifi_roles[ridx];
if(wr->active != true || wr->mstate != MLME_LINKED)
continue;
if (rtw_phl_role_is_client_category(wr)) {
mctx.role_map_ps |= BIT(ridx);
} else if (rtw_phl_role_is_ap_category(wr) ||
wr->type == PHL_RTYPE_MESH) {
mctx.role_map_ap |= BIT(ridx);
}
}
}
}
_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
if (!found) {
PHL_DBG("No chanctx is the same as current channel!\n");
goto _exit;
}
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if ((mctx.role_map_ap) && (mctx.role_map_ap & BIT(ridx))) {
wr = &phl_com->wifi_roles[ridx];
psts = _phl_wr_offch_bcn_hdl(phl_info, hw_band, wr, off_ch);
if (psts == RTW_PHL_STATUS_FAILURE) {
PHL_ERR("%s ridx:%d _phl_wr_offch_bcn_hdl failed\n",
__func__, ridx);
break;
}
}
/* issue null-data on current channel */
if ((mctx.role_map_ps) && (mctx.role_map_ps & BIT(ridx))) {
wr = &phl_com->wifi_roles[ridx];
#ifdef RTW_WKARD_TXPAUSE_BF_ISSUE_NULL
if (off_ch && rtw_phl_cmd_scan_inprogress(phl_info, hw_band))
rtw_hal_scan_pause_tx_fifo(phl_info->hal, hw_band, true);
#endif
psts = _phl_wr_offch_ps_hdl(phl_info, hw_band, wr, off_ch,
obj_priv, module_id,
issue_null_data);
if (psts == RTW_PHL_STATUS_FAILURE) {
PHL_ERR("%s ridx:%d _phl_wr_offch_ps_hdl failed\n",
__func__, ridx);
break;
}
}
}
_exit:
#ifdef DBG_DBCC_MONITOR_TIME
PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
return psts;
}
#else /*!CONFIG_MR_SUPPORT*/
static enum rtw_phl_status
_phl_wr_offch_hdl(struct phl_info_t *phl_info,
u8 hw_band,
struct rtw_wifi_role_t *wrole,
bool off_ch,
void *obj_priv,
u8 module_id,
bool (*issue_null_data)(void *priv, u8 ridx,
u8 lidx, bool ps, u8 module_id))
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
void *drv = phl_to_drvpriv(phl_info);
struct rtw_chan_ctx *chanctx = NULL;
u8 cur_ch = rtw_hal_get_cur_ch(phl_info->hal, hw_band);
bool found = false;
int ctx_num = 0;
#ifdef DBG_MONITOR_TIME
u32 start_t = 0;
PHL_FUN_MON_START(&start_t);
#endif /* DBG_MONITOR_TIME */
ctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
if (ctx_num == 0){
PHL_DBG("ctx_num == 0!\n");
goto _exit;
}
_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {
/* Find the chanctx same as the current channel */
if(chanctx->chan_def.chan != cur_ch)
continue;
PHL_DBG("%s current chanctx found!\n", __FUNCTION__);
found = true;
}
_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
if (!found) {
PHL_DBG("No chanctx is the same as current channel!\n");
goto _exit;
}
if (rtw_phl_role_is_client_category(wrole)
&& wrole->mstate == MLME_LINKED) {
if(issue_null_data == NULL){
PHL_ERR("%s issue null_data function not found\n", __func__);
_os_warn_on(1);
goto _exit;
}
#ifdef RTW_WKARD_TXPAUSE_BF_ISSUE_NULL
if (off_ch && rtw_phl_cmd_scan_inprogress(phl_info, hw_band))
rtw_hal_scan_pause_tx_fifo(phl_info->hal, hw_band, true);
#endif
psts = _phl_wr_offch_ps_hdl(phl_info,
hw_band,
wrole,
off_ch,
obj_priv,
module_id,
issue_null_data);
} else if (rtw_phl_role_is_ap_category(wrole)) {
psts = _phl_wr_offch_bcn_hdl(phl_info,
hw_band,
wrole,
off_ch);
}
_exit:
#ifdef DBG_MONITOR_TIME
PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_MONITOR_TIME */
return psts;
}
#endif
enum rtw_phl_status
phl_mr_offch_hdl(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink,
bool off_ch,
void *obj_priv,
u8 module_id,
bool (*issue_null_data)(void *priv, u8 ridx, u8 lidx,
bool ps, u8 module_id)
)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
#ifdef CONFIG_MR_SUPPORT
psts = _phl_mr_offch_hdl(phl_info, rlink->hw_band, off_ch, obj_priv,
module_id, issue_null_data);
#else /*!CONFIG_MR_SUPPORT*/
psts = _phl_wr_offch_hdl(phl_info, rlink->hw_band, wrole,
off_ch, obj_priv, module_id, issue_null_data);
#endif
return psts;
}
#ifdef CONFIG_DBCC_SUPPORT
bool rtw_phl_mr_is_db(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
return (mr_ctl->is_db == true) ? true : false;
}
bool phl_mr_is_cckphy(struct phl_info_t *phl_info, u8 band_idx)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
return (mr_ctl->cck_phyidx == band_idx) ? true : false;
}
void rtw_phl_mr_cancel_dbcc_action(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
#ifdef CONFIG_DBCC_FORCE
if (is_frc_dbcc_mode(phl_info->phl_com)) {
PHL_ERR("%s FORCE DBCC .....\n", __func__);
return;
}
#endif
_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
mr_ctl->trigger_dbcc_cfg = false;
_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
}
bool phl_mr_is_trigger_dbcc(struct phl_info_t *phl_info)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
return mr_ctl->trigger_dbcc_cfg;
}
enum rtw_phl_status
phl_mr_trig_dbcc_enable(struct phl_info_t *phl_info, bool trig)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
/*hal_com->dbcc_en*/
if (trig == true) {
_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
if (mr_ctl->is_db == false) /*single band*/
mr_ctl->trigger_dbcc_cfg = true;
_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
} else {
_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
mr_ctl->trigger_dbcc_cfg = false;
mr_ctl->is_db = true;
_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
}
return RTW_PHL_STATUS_SUCCESS;
}
enum rtw_phl_status
rtw_phl_mr_trig_dbcc_enable(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
#ifdef CONFIG_DBCC_FORCE
if (is_frc_dbcc_mode(phl_info->phl_com)) {
PHL_INFO("%s FORCE DBCC .....\n", __func__);
return RTW_PHL_STATUS_SUCCESS;
}
#endif
return phl_mr_trig_dbcc_enable(phl_info, true);
}
static inline enum rtw_phl_status
phl_mr_dbcc_proto_hdl(struct phl_info_t *phl_info,
enum phl_band_idx band_idx,
struct rtw_wifi_role_t *wrole,
bool dbcc_en)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct dbcc_proto_msg dbcc_proto = {0};
u8 ret = _FAIL;
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
dbcc_proto.dbcc_en = dbcc_en;
dbcc_proto.wr = wrole;
ret = mr_ctl->mr_ops.dbcc_protocol_hdl(phl_com->drv_priv, band_idx, &dbcc_proto);
#ifdef DBG_DBCC_MONITOR_TIME
PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
return (ret == _SUCCESS) ? RTW_PHL_STATUS_SUCCESS
: RTW_PHL_STATUS_FAILURE;
}
enum rtw_phl_status
rtw_phl_mr_dbcc_enable(void *phl,
enum phl_band_idx band_idx,
struct rtw_wifi_role_t *wrole)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_msg msg = {0};
struct phl_msg_attribute attr = {0};
enum rtw_phl_status psts;
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_MRC);
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_DBCC_ENABLE);
msg.band_idx = band_idx;
msg.inbuf = (u8 *)wrole;
psts = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s: Dispr send msg fail!\n", __func__);
}
return psts;
}
static void _phl_mr_pause_trx(struct phl_info_t *phl_info, enum phl_band_idx band_idx)
{
enum rtw_phl_status sts = RTW_PHL_STATUS_FAILURE;
struct phl_data_ctl_t ctl = {0};
struct phl_hci_trx_ops *hci_trx_ops = phl_info->hci_trx_ops;
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
ctl.id = PHL_MDL_MRC;
ctl.cmd = PHL_DATA_CTL_SW_TX_PAUSE;
sts = phl_data_ctrler(phl_info, &ctl, NULL);
if (RTW_PHL_STATUS_SUCCESS != sts) {
PHL_ERR("%s(): pause sw tx failure\n", __func__);
goto err;
}
/* Stop DMA + Disable all of txch dma (Reset B1 TXBD idx to 0) */
rtw_hal_dbcc_hci_ctrl(phl_info->hal, band_idx, true);
/* - Redirect packets from old_band(B1) to new_band(B0)
* [PCIE] Memory copy band1 TXBD to band0 DMA channel, update WD (DMA_CH/QSEL/...)
* - Or drop packets
*/
if (band_idx == HW_BAND_1)
hci_trx_ops->tx_reset_hwband(phl_info, band_idx);
err:
#ifdef DBG_DBCC_MONITOR_TIME
PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
return;
}
static void _phl_mr_resume_trx(struct phl_info_t *phl_info, enum phl_band_idx band_idx)
{
enum rtw_phl_status sts = RTW_PHL_STATUS_FAILURE;
struct phl_data_ctl_t ctl = {0};
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
/* Enable all of txch dma */
rtw_hal_dbcc_hci_ctrl(phl_info->hal, band_idx, false);
ctl.id = PHL_MDL_MRC;
ctl.cmd = PHL_DATA_CTL_SW_TX_RESUME;
sts = phl_data_ctrler(phl_info, &ctl, NULL);
if (RTW_PHL_STATUS_SUCCESS != sts) {
PHL_ERR("%s(): resume sw tx failure\n", __func__);
goto err;
}
err:
#ifdef DBG_DBCC_MONITOR_TIME
PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
return;
}
enum phl_mdl_ret_code
_phl_mrc_module_dbcc_en_hdl(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *role)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_wifi_role_link_t *rlink = NULL;
bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;
struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
struct rtw_chan_def op_chdef = {0};
u8 hal_ch = 0;
int chctx_num;
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: Rid(%d)\n",
__FUNCTION__, role->id);
rlink = &role->rlink[RTW_RLINK_PRIMARY];
if (rlink->hw_band != HW_BAND_0) {
PHL_ERR("wrole(%d) not in band0\n", role->id);
_os_warn_on(1);
ret = MDL_RET_FAIL;
goto _exit;
}
hal_ch = rtw_hal_get_cur_ch(phl_info->hal, rlink->hw_band);
/* 1.issue null(1) - pause Rx*/
/*switch ch to op-chan*/
chctx_num = phl_mr_get_chandef_by_band(phl_info, rlink->hw_band, &op_chdef);
PHL_DUMP_CHAN_DEF_EX(&op_chdef);
hal_ch = rtw_hal_get_cur_ch(phl_info->hal, rlink->hw_band);
if (chctx_num == 1) {
if (hal_ch != op_chdef.chan) {
PHL_ERR("hw chan(%d) not in op-chan(%d)\n", hal_ch, op_chdef.chan);
phl_set_ch_bw(phl_info, rlink->hw_band, &op_chdef, RFK_TYPE_DBCC_EN);
}
}
if (ops->issue_null_data)
core_issue_null_data = ops->issue_null_data;
_phl_mr_offch_hdl(phl_info,
HW_BAND_0,
true,
phl_com->drv_priv,
PHL_MDL_MRC,
core_issue_null_data);
/* 2.pause Tx- SW,HW*/
_phl_mr_pause_trx(phl_info, HW_BAND_0);
rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, true);
/* 3.dbcc hw cfg (en)*/
rtw_hal_dbcc_pre_cfg(phl_info->hal, phl_com, true);
rtw_hal_dbcc_cfg(phl_info->hal, phl_com, true);
/* 4.reallocate hw resouce - role*/
phl_wifi_role_realloc_band(phl_info, role, rlink, HW_BAND_1);
rtw_hal_dbcc_reset_hal(phl_info->hal);
rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, false);
rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_1, false);
/* 5.unpause Tx- SW,HW*/
_phl_mr_resume_trx(phl_info, HW_BAND_0);
/* 6.issue null(0) - unpause Rx*/
_phl_mr_offch_hdl(phl_info,
HW_BAND_0,
false,
phl_com->drv_priv,
PHL_MDL_MRC,
core_issue_null_data);
phl_mr_trig_dbcc_enable(phl_info, false);
ret = MDL_RET_SUCCESS;
PHL_INFO("%s wr(%d) success....\n", __func__, role->id);
_exit:
#ifdef DBG_DBCC_MONITOR_TIME
PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
return ret;
}
enum phl_mdl_ret_code
_phl_mrc_module_dbcc_enable(void *dispr,
void *priv,
struct phl_msg *msg)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct rtw_wifi_role_t *role = NULL;
u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);
if (module_id != PHL_MDL_MRC) {
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s: not mrc\n", __FUNCTION__);
return MDL_RET_IGNORE;
}
role = (struct rtw_wifi_role_t *)msg->inbuf;
return _phl_mrc_module_dbcc_en_hdl(phl_info, role);
}
enum rtw_phl_status
phl_mr_trig_dbcc_disable(struct phl_info_t *phl_info, bool trig)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
/*hal_com->dbcc_en*/
if (trig == true) {
_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
if (mr_ctl->is_db == true) /*dual band*/
mr_ctl->trigger_dbcc_cfg = true;
_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
} else {
_os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
mr_ctl->trigger_dbcc_cfg = false;
mr_ctl->is_db = false;
_os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL);
}
return RTW_PHL_STATUS_SUCCESS;
}
enum rtw_phl_status
rtw_phl_mr_trig_dbcc_disable(void *phl)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
#ifdef CONFIG_DBCC_FORCE
if (is_frc_dbcc_mode(phl_info->phl_com)) {
PHL_INFO("%s FORCE DBCC .....\n", __func__);
return RTW_PHL_STATUS_SUCCESS;
}
#endif
return phl_mr_trig_dbcc_disable(phl_info, true);
}
enum rtw_phl_status
rtw_phl_mr_dbcc_disable(void *phl,
enum phl_band_idx band_idx,
struct rtw_wifi_role_t *wrole)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_msg msg = {0};
struct phl_msg_attribute attr = {0};
enum rtw_phl_status psts;
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_MRC);
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_DBCC_DISABLE);
msg.band_idx = band_idx;
msg.inbuf = (u8 *)wrole;
psts = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s: Dispr send msg fail!\n", __func__);
}
return psts;
}
static inline void
_phl_mr_band_info_cleanup(struct rtw_phl_com_t *phl_com, struct hw_band_ctl_t *band_ctrl)
{
_os_mem_set(phl_com->drv_priv, &band_ctrl->cur_info, 0, sizeof(struct mr_info));
band_ctrl->port_map = 0;
band_ctrl->role_map = 0;
band_ctrl->wmm_map = 0;
band_ctrl->op_mode = MR_OP_NONE;
band_ctrl->op_type = MR_OP_TYPE_NONE;
band_ctrl->chctx_band_map = 0;
if (band_ctrl->chan_ctx_queue.cnt) {
PHL_ERR("%s Band_%d chan_ctx_queue.cnt(%d) not clearn up\n",
__func__, band_ctrl->id, band_ctrl->chan_ctx_queue.cnt);
_os_warn_on(1);
}
}
static enum rtw_phl_status
_phl_dbcc_sync_rxfilter(struct phl_info_t *phl_info, enum phl_band_idx band_idx)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
struct rtw_wifi_role_t *role = NULL, *wr = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 ridx = 0;
enum rtw_phl_status ret = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s: band=%d\n", __func__, band_idx);
wr = phl_mr_get_role_by_bandidx(phl_info, band_idx);
if (wr == NULL) {
PHL_INFO("%s: can't find any role for band(%d)\n", __func__, band_idx);
_os_warn_on(1);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
rlink = &wr->rlink[0];
ret = phl_mr_info_upt(phl_info, rlink);
if (ret != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s: phl_mr_info_upt fail(%d)\n", __func__, ret);
goto exit;
}
ret = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
if (ret != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s: rtw_phl_mr_rx_filter_opt fail(%d)\n", __func__, ret);
goto exit;
}
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (band_ctrl->role_map & BIT(ridx)) {
role = &(phl_com->wifi_roles[ridx]);
rlink = &role->rlink[0];
if (role->mstate == MLME_LINKED && rtw_phl_role_is_client_category(role)) {
ret = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink, RX_FLTR_TYPE_MODE_STA_CONN);
if (ret != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s: rxfltr_type_by_mode fail(%d), role id=%d, rlink id=%d, mode=%d\n",
__func__, ret, role->id, rlink->id, RX_FLTR_TYPE_MODE_STA_CONN);
goto exit;
}
}
if (rtw_phl_role_is_ap_category(role)) {
ret = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink, RX_FLTR_TYPE_MODE_AP_CONN);
if (ret != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s: rxfltr_type_by_mode fail(%d), id=%d, rlink id=%d, mode=%d\n",
__func__, ret, role->id, rlink->id, RX_FLTR_TYPE_MODE_AP_CONN);
goto exit;
}
}
}
}
exit:
return ret;
}
static enum phl_mdl_ret_code
_phl_mrc_module_dbcc_dis_pre_hdl(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *role)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band0_ctrl = &(mr_ctl->band_ctrl[HW_BAND_0]);
struct hw_band_ctl_t *band1_ctrl = &(mr_ctl->band_ctrl[HW_BAND_1]);
struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
struct rtw_chan_def op_chdef = {0};
u8 role_num = 0, ridx;
struct rtw_wifi_role_t *wr = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;
int chctx_num = 0;
enum phl_band_idx band_idx = HW_BAND_0;
u8 hal_ch = 0;
int b0_chctx_num = 0;
int b1_chctx_num = 0;
bool rd_enabled = false;
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
PHL_FUN_MON_START(&start_t);
#endif /* DBG_DBCC_MONITOR_TIME */
rlink = &role->rlink[RTW_RLINK_PRIMARY];
if (ops->issue_null_data)
core_issue_null_data = ops->issue_null_data;
if (rlink->hw_band == HW_BAND_0)
band_idx = HW_BAND_1;
b0_chctx_num = phl_mr_get_chanctx_num(phl_info, band0_ctrl);
PHL_INFO("%s Band_0 has chctx_num(%d)\n", __func__, b0_chctx_num);
b1_chctx_num = phl_mr_get_chanctx_num(phl_info, band1_ctrl);
PHL_INFO("%s Band_1 has chctx_num(%d)\n", __func__, b1_chctx_num);
chctx_num = phl_mr_get_chandef_by_band(phl_info, band_idx, &op_chdef);
PHL_INFO("Band_%d - op ch(%d), band(%d), offset(%d)\n",
band_idx, op_chdef.chan, op_chdef.band, op_chdef.offset);
if (chctx_num >= 1) {
/*TODO - chctx_num == 2, get first chan_ctx*/
hal_ch = rtw_hal_get_cur_ch(phl_info->hal, band_idx);
if (hal_ch != op_chdef.chan) {
PHL_ERR("hw chan(%d) not in op-chan(%d)\n", hal_ch, op_chdef.chan);
phl_set_ch_bw(phl_info, band_idx, &op_chdef, RFK_TYPE_DBCC_DIS);
}
}
/* 1.issue null(1) - pause Rx,stop beacon*/
_phl_mr_offch_hdl(phl_info,
band_idx,
true,
phl_com->drv_priv,
PHL_MDL_MRC,
core_issue_null_data);
/* 2.pause Tx- SW,HW*/
_phl_mr_pause_trx(phl_info, HW_BAND_1);
rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, true);
rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_1, true);
/* 3.reallocate hw resouce all of role in band 1,before disable cmac1*/
role_num = phl_mr_get_role_num(phl_info, band1_ctrl);
if (role_num == 0) {
PHL_ERR("BAND_1 role num == 0\n");
_os_warn_on(1);
}
PHL_INFO("%s band-1 - role_num:%d\n", __func__, role_num);
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (band1_ctrl->role_map & BIT(ridx)) {
wr = &(phl_com->wifi_roles[ridx]);
psts = phl_wifi_role_realloc_band(phl_info, wr, &wr->rlink[RTW_RLINK_PRIMARY], HW_BAND_0);
if (psts == RTW_PHL_STATUS_FAILURE) {
PHL_ERR("%s phl_wifi_role_realloc_band failed\n",
__func__);
break;
}
}
}
/* 4.move bnad1's chan_ctx to band0*/
if (b1_chctx_num) {
if (b0_chctx_num != 0) {
PHL_ERR("%s Band_0 has chctx_num(%d)\n", __func__, b0_chctx_num);
_os_warn_on(1);
}
phl_chanctx_switch(phl_info, band0_ctrl, band1_ctrl);
rtw_hal_dbcc_band_switch_hdl(phl_info->hal, HW_BAND_1);
}
/* 5.dbcc hw cfg (en = false)*/
rtw_hal_dbcc_pre_cfg(phl_info->hal, phl_com, false);
rtw_hal_dbcc_cfg(phl_info->hal, phl_com, false);
/* 6. clean up all of sw vaule of band1*/
_phl_mr_band_info_cleanup(phl_com, band1_ctrl);
/* 7. restore_phy0_ch*/
#ifdef CONFIG_PHL_DFS
rd_enabled = rtw_phl_is_radar_detect_enabled(phl_com, HW_BAND_0);
#endif
rtw_hal_set_ch_bw(phl_info->hal, HW_BAND_0, &op_chdef, RFK_TYPE_FORCE_DO, rd_enabled, true);
PHL_INFO("restore_phy0_ch - ch(%d), band(%d), offset(%d)\n",
op_chdef.chan, op_chdef.band, op_chdef.offset);
rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_0, false);
rtw_hal_dbcc_trx_ctrl(phl_info->hal, phl_com, HW_BAND_1, false);
/* 8. unpause Tx- SW,HW*/
_phl_mr_resume_trx(phl_info, HW_BAND_0);
/* 9. check rx filter before unpause RX */
_phl_dbcc_sync_rxfilter(phl_info, HW_BAND_0);
/* 10. issue null(0) - unpause Rx*/
_phl_mr_offch_hdl(phl_info,
HW_BAND_0,
false,
phl_com->drv_priv,
PHL_MDL_MRC,
core_issue_null_data);
ret = MDL_RET_SUCCESS;
#ifdef DBG_DBCC_MONITOR_TIME
PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_MAX);
#endif /* DBG_DBCC_MONITOR_TIME */
return ret;
}
static enum phl_mdl_ret_code
_phl_mrc_module_dbcc_dis_post_hdl(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *role)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
phl_mr_trig_dbcc_disable(phl_info, false);
rtw_hal_notification(phl_info->hal,
MSG_EVT_DBCC_DISABLE,
HW_BAND_0);
ret = MDL_RET_SUCCESS;
return ret;
}
enum phl_mdl_ret_code
_phl_mrc_module_dbcc_disable(void *dispr,
void *priv,
struct phl_msg *msg)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct rtw_wifi_role_t *role = NULL;
u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
phl_fun_monitor_start(&start_t, true, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
if ((module_id != PHL_MDL_MRC) &&
(module_id != PHL_FG_MDL_DISCONNECT) &&
(module_id != PHL_FG_MDL_CONNECT) &&
(module_id != PHL_FG_MDL_AP_STOP) &&
(module_id != PHL_FG_MDL_AP_START)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s: msg not from DISC-CONT/AP-STOP/START FG or MRC\n", __FUNCTION__);
ret = MDL_RET_IGNORE;
goto _exit;
}
role = (struct rtw_wifi_role_t *)msg->inbuf;
if ((MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_DISCONNECT_END) ||
(MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_AP_STOP_END)) {
ret = _phl_mrc_module_dbcc_dis_pre_hdl(phl_info, role);
PHL_INFO("%s wr(%d) phase-1 success....\n", __func__, role->id);
}
else if (MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_DBCC_DISABLE) {
ret = _phl_mrc_module_dbcc_dis_post_hdl(phl_info, role);
PHL_INFO("%s wr(%d) phase-2 success....\n", __func__, role->id);
}
_exit:
#ifdef DBG_DBCC_MONITOR_TIME
phl_fun_monitor_end(phl_info->phl_com, &start_t, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
return ret;
}
#ifdef CONFIG_DBCC_P2P_BG_LISTEN
static inline enum rtw_phl_status
phl_mr_dbcc_proto_hdl_ex(struct phl_info_t *phl_info,
enum phl_band_idx band_idx,
struct rtw_wifi_role_t *wrole,
bool dbcc_en)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct dbcc_proto_msg dbcc_proto = {0};
u8 ret = _FAIL;
#ifdef DBG_DBCC_MONITOR_TIME
u32 start_t = 0;
phl_fun_monitor_start(&start_t, true, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
dbcc_proto.dbcc_en = dbcc_en;
dbcc_proto.wr = wrole;
dbcc_proto.dbcc_cmd_direct = true;
ret = mr_ctl->mr_ops.dbcc_protocol_hdl(phl_com->drv_priv, band_idx, &dbcc_proto);
#ifdef DBG_DBCC_MONITOR_TIME
phl_fun_monitor_end(phl_info->phl_com, &start_t, __FUNCTION__);
#endif /* DBG_DBCC_MONITOR_TIME */
return (ret == _SUCCESS) ? RTW_PHL_STATUS_SUCCESS
: RTW_PHL_STATUS_FAILURE;
}
enum rtw_phl_status
_phl_mrc_module_dbcc_enable_ex(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
psts = phl_mr_dbcc_proto_hdl_ex(phl_info, wrole->rlink->hw_band, wrole, true);
ret = _phl_mrc_module_dbcc_en_hdl(phl_info, wrole);
PHL_DUMP_MR_EX(phl_info);
return psts;
}
enum rtw_phl_status
phl_cmd_dbcc_en_hdl(struct phl_info_t *phl_info, u8 *param)
{
struct rtw_wifi_role_t *wrole = (struct rtw_wifi_role_t *)param;
return _phl_mrc_module_dbcc_enable_ex(phl_info, wrole);
}
enum rtw_phl_status
rtw_phl_cmd_dbcc_enable(struct rtw_wifi_role_t *wifi_role,
u8 band_idx,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
struct phl_info_t *phl_info = wifi_role->phl_com->phl_priv;
void *drv = wifi_role->phl_com->drv_priv;
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
if (cmd_type == PHL_CMD_DIRECTLY) {
psts = _phl_mrc_module_dbcc_enable_ex(phl_info, wifi_role);
goto _exit;
}
psts = phl_cmd_enqueue(phl_info,
band_idx,
MSG_EVT_DISCONNECT_CMD_DBCC_EN,
(u8 *)wifi_role,
0,
NULL,
cmd_type,
cmd_timeout);
if (is_cmd_failure(psts)) {
/* Send cmd success, but wait cmd fail*/
psts = RTW_PHL_STATUS_FAILURE;
} else if (psts != RTW_PHL_STATUS_SUCCESS) {
psts = RTW_PHL_STATUS_FAILURE;
}
_exit:
return psts;
}
enum rtw_phl_status
_phl_mrc_module_dbcc_disable_ex(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
ret = _phl_mrc_module_dbcc_dis_pre_hdl(phl_info, wrole);
ret = _phl_mrc_module_dbcc_dis_post_hdl(phl_info, wrole);
psts = phl_mr_dbcc_proto_hdl_ex(phl_info, wrole->rlink->hw_band, wrole, false);
PHL_DUMP_MR_EX(phl_info);
return psts;
}
enum rtw_phl_status
phl_cmd_dbcc_dis_hdl(struct phl_info_t *phl_info, u8 *param)
{
struct rtw_wifi_role_t *wrole = (struct rtw_wifi_role_t *)param;
return _phl_mrc_module_dbcc_disable_ex(phl_info, wrole);
}
enum rtw_phl_status
rtw_phl_cmd_dbcc_disable(struct rtw_wifi_role_t *wifi_role,
u8 band_idx,
enum phl_cmd_type cmd_type,
u32 cmd_timeout)
{
struct phl_info_t *phl_info = wifi_role->phl_com->phl_priv;
void *drv = wifi_role->phl_com->drv_priv;
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
if (cmd_type == PHL_CMD_DIRECTLY) {
psts = _phl_mrc_module_dbcc_disable_ex(phl_info, wifi_role);
goto _exit;
}
psts = phl_cmd_enqueue(phl_info,
band_idx,
MSG_EVT_CONNECT_CMD_DBCC_DIS,
(u8 *)wifi_role,
0,
NULL,
cmd_type,
cmd_timeout);
if (is_cmd_failure(psts)) {
/* Send cmd success, but wait cmd fail*/
psts = RTW_PHL_STATUS_FAILURE;
} else if (psts != RTW_PHL_STATUS_SUCCESS) {
psts = RTW_PHL_STATUS_FAILURE;
}
_exit:
return psts;
}
#endif /*CONFIG_DBCC_P2P_BG_LISTEN*/
#endif /*CONFIG_DBCC_SUPPORT*/
#ifdef CONFIG_CMD_DISP
static enum phl_mdl_ret_code
_phl_mrc_module_init(void *phl_info, void *dispr, void **priv)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
FUNCIN();
*priv = phl_info;
FUNCOUT();
ret = MDL_RET_SUCCESS;
return ret;
}
static void
_phl_mrc_module_deinit(void *dispr, void *priv)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
FUNCIN();
FUNCOUT();
ret = MDL_RET_SUCCESS;
}
static enum phl_mdl_ret_code
_phl_mrc_module_start(void *dispr, void *priv)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
FUNCIN();
#ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP
/* Ensure M-BSSID map cleaned up in case of VAP roles were not turned
off normally. */
do {
struct mr_ctl_t *mr_ctl = phl_to_mr_ctrl(priv);
u8 band_idx = 0;
for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
band_ctrl->mbssid_map = 0;
band_ctrl->mbssid_cnt = 0;
}
} while (0);
#endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */
FUNCOUT();
ret = MDL_RET_SUCCESS;
return ret;
}
static enum phl_mdl_ret_code
_phl_mrc_module_stop(void *dispr, void *priv)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
FUNCIN();
FUNCOUT();
ret = MDL_RET_SUCCESS;
return ret;
}
/* Same behaviour as rtw_phl_connect_prepare without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_connect_start_hdlr(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
__func__, wrole->id);
if (rtw_phl_role_is_client_category(wrole)) {
wrole->mstate = MLME_LINKING;
}
psts = phl_mr_info_upt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr info upt failed\n", __func__);
goto _exit;
}
if (!rtw_phl_role_is_ap_category(wrole)) {
psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
goto _exit;
}
}
PHL_DUMP_MR_EX(phl_info);
_exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
__func__, psts);
return psts;
}
/* Same behaviour as rtw_phl_connected without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_connect_end_hdlr(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
u8 idx = 0;
struct rtw_wifi_role_link_t *rlink = NULL;
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
__func__, wrole->id);
if (rtw_phl_role_is_client_category(wrole)) {
psts = phl_role_notify(phl_info, wrole);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s sta role notify failed\n", __func__);
goto _exit;
}
}
if (!rtw_phl_role_is_ap_category(wrole)) {
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
if (rlink->mstate != MLME_LINKED)
continue;
psts = phl_mr_info_upt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr info upt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
RX_FLTR_TYPE_MODE_STA_CONN);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
goto _exit;
}
psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_STA_CONN_END);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
goto _exit;
}
}
} else {
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
psts = phl_mr_info_upt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr info upt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
RX_FLTR_TYPE_MODE_AP_CONN);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
goto _exit;
}
}
}
PHL_DUMP_MR_EX(phl_info);
_exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
__func__, psts);
return psts;
}
/* Same behaviour as rtw_phl_disconnect without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_disconnect_hdlr(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
u8 idx = 0;
struct rtw_wifi_role_link_t *rlink = NULL;
#ifdef CONFIG_PHL_TDLS
enum role_type rtype = PHL_RTYPE_STATION;
#endif
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
__func__, wrole->id);
#ifdef CONFIG_PHL_TDLS
/* Disconnected with AP while there still exist linked TDLS peers */
if (wrole->type == PHL_RTYPE_TDLS && wrole->mstate != MLME_LINKED) {
psts = phl_wifi_role_change(phl_info, wrole, NULL, WR_CHG_TYPE, (u8*)&rtype);
if (psts != RTW_PHL_STATUS_SUCCESS) {
RTW_ERR("%s - change to phl role type = %d fail with error = %d\n", __func__, rtype, psts);
goto _exit;
}
}
#endif
if (rtw_phl_role_is_client_category(wrole)) {
psts = phl_role_notify(phl_info, wrole);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s sta role notify failed\n", __func__);
goto _exit;
}
}
if (!rtw_phl_role_is_ap_category(wrole)) {
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
psts = phl_mr_info_upt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr info upt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
RX_FLTR_TYPE_MODE_STA_DIS_CONN);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
goto _exit;
}
psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_STA_DIS_CONN);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
goto _exit;
}
rtw_hal_disconnect_notify(phl_info->hal, &rlink->chandef);
}
} else {
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
psts = phl_mr_info_upt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr info upt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink,
RX_FLTR_TYPE_MODE_AP_DIS_CONN);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_type failed\n", __func__);
goto _exit;
}
}
}
PHL_DUMP_MR_EX(phl_info);
_exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
__func__, psts);
return psts;
}
/* Same behaviour as rtw_phl_ap_started without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_ap_started_hdlr(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
__func__, wrole->id);
psts = phl_role_notify(phl_info, wrole);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s role notify failed\n", __func__);
goto _exit;
}
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
psts = phl_mr_info_upt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr info upt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
goto _exit;
}
psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_AP_START);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
goto _exit;
}
}
PHL_DUMP_MR_EX(phl_info);
_exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
__func__, psts);
return psts;
}
/* Same behaviour as rtw_phl_ap_stop without cmd dispr */
enum rtw_phl_status
_phl_mrc_module_ap_stop_hdlr(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
u8 idx = 0;
struct rtw_wifi_role_link_t *rlink = NULL;
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
__func__, wrole->id);
wrole->mstate = MLME_NO_LINK;
psts = phl_role_notify(phl_info, wrole);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s role notify failed\n", __func__);
goto _exit;
}
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
rtw_hal_disconnect_drop_all_pkt(phl_info->hal,
rtw_phl_get_stainfo_self(phl_info, rlink));
psts = phl_mr_info_upt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr info upt failed\n", __func__);
goto _exit;
}
psts = rtw_phl_mr_rx_filter_opt(phl_info, rlink);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_rx_filter_opt failed\n", __func__);
goto _exit;
}
psts = phl_mr_tsf_sync(phl_info, wrole, rlink, PHL_ROLE_MSTS_AP_STOP);
if (psts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s set mr_tsf_sync failed\n", __func__);
goto _exit;
}
rtw_hal_disconnect_notify(phl_info->hal, &rlink->chandef);
}
PHL_DUMP_MR_EX(phl_info);
_exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
__func__, psts);
return psts;
}
enum phl_mdl_ret_code
_phl_mrc_module_swch_start_hdlr(void *dispr,
void *priv,
struct phl_msg *msg)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct phl_module_op_info op_info = {0};
struct rtw_wifi_role_t *role = NULL;
struct rtw_chan_def chandef = {0};
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);
struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
u8 idx = 0xff, hw_band = 0;
struct rtw_wifi_role_link_t *rlink = NULL;
bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;
phl_dispr_get_idx(dispr, &idx);
/*
* Handle mr offchan before switching channel when
* STA connect & AP start.
*/
if((module_id != PHL_FG_MDL_CONNECT) &&
(module_id != PHL_FG_MDL_AP_START) &&
(module_id != PHL_FG_MDL_SCAN)){
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s: not connect/apstart/scan\n", __FUNCTION__);
ret = MDL_RET_IGNORE;
goto _exit;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_SWCH_START\n", __FUNCTION__, msg->band_idx);
op_info.op_code = FG_REQ_OP_GET_ROLE;
if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
!= RTW_PHL_STATUS_SUCCESS){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"Query wifi role fail!\n");
goto _exit;
}
role = (struct rtw_wifi_role_t *)op_info.outbuf;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
goto _exit;
}
op_info.op_code = FG_REQ_OP_GET_ROLE_LINK;
if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
!= RTW_PHL_STATUS_SUCCESS){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"Query wifi role link fail!\n");
goto _exit;
}
rlink = (struct rtw_wifi_role_link_t *)op_info.outbuf;
if(rlink == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role link is NULL\n", __FUNCTION__);
goto _exit;
}
hw_band = rlink->hw_band;
/*
* If we are already on STA/AP channel,
* offch is unnecessary.
*/
if((module_id == PHL_FG_MDL_CONNECT) ||
(module_id == PHL_FG_MDL_AP_START)){
#ifdef CONFIG_MR_SUPPORT
chandef = mr_ctl->hal_com->band[hw_band].cur_chandef;
if(rlink->chandef.chan == chandef.chan){
ret = MDL_RET_SUCCESS;
goto _exit;
}
#else
ret = MDL_RET_SUCCESS;
goto _exit;
#endif
}
if (ops->issue_null_data)
core_issue_null_data = ops->issue_null_data;
phl_mr_offch_hdl(phl_info,
role,
rlink,
true,
phl_com->drv_priv,
module_id,
core_issue_null_data);
ret = MDL_RET_SUCCESS;
_exit:
return ret;
}
enum phl_mdl_ret_code
_phl_mrc_module_swch_done_hdlr(void *dispr,
void *priv,
struct phl_msg *msg)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_wifi_role_t *role = NULL;
u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id);
struct phl_scan_channel scan_ch = {0};
struct rtw_phl_evt_ops *ops = &phl_info->phl_com->evt_ops;
struct rtw_wifi_role_link_t *rlink = NULL;
bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;
/*
* Handle mr offchan after switching channel to op channel
*/
if(module_id != PHL_FG_MDL_SCAN){
ret = MDL_RET_IGNORE;
goto _exit;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_SWCH_DONE\n", __FUNCTION__, msg->band_idx);
scan_ch = *(struct phl_scan_channel *)(msg->inbuf);
/* Issue null 0 and resume beacon when BACKOP during scanning */
if(scan_ch.scan_mode != BACKOP_MODE){
ret = MDL_RET_SUCCESS;
goto _exit;
}
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[1].ptr;
if (ops->issue_null_data)
core_issue_null_data = ops->issue_null_data;
phl_mr_offch_hdl(phl_info,
role,
rlink,
false,
phl_com->drv_priv,
module_id,
core_issue_null_data);
ret = MDL_RET_SUCCESS;
_exit:
return ret;
}
static enum rtw_phl_status
_mrc_module_chg_op_chdef_end_pre_hdlr(u8 *param)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct chg_opch_param *ch_param = (struct chg_opch_param *)param;
struct rtw_wifi_role_t *wrole = ch_param->wrole;
struct phl_info_t *phl = wrole->phl_com->phl_priv;
struct rtw_phl_evt_ops *ops = &phl->phl_com->evt_ops;
bool (*core_issue_null)(void *, u8, u8, bool, u8) = NULL;
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: wrole->id(%d)\n",
__func__, wrole->id);
/* Handle mr offchan after switching channel to new op channel */
/* If the new pri-ch is as same as ori pri-ch, offch is unnecessary. */
if(ch_param->new_chdef.chan == ch_param->ori_chdef.chan) {
psts = RTW_PHL_STATUS_SUCCESS;
goto exit;
}
if (ops->issue_null_data) {
core_issue_null = ops->issue_null_data;
} else {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Ops issue_null_data is NULL\n",
__func__);
}
if (RTW_PHL_STATUS_SUCCESS != phl_mr_offch_hdl(phl,
wrole,
ch_param->rlink,
false,
phl->phl_com->drv_priv,
PHL_MDL_MRC,
core_issue_null)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "%s: Fail to offch\n",
__func__);
goto exit;
}
psts = RTW_PHL_STATUS_SUCCESS;
exit:
PHL_TRACE(COMP_PHL_MCC, _PHL_INFO_, "%s: psts(%d)\n",
__func__, psts);
return psts;
}
static enum phl_mdl_ret_code
_mrc_module_chg_op_chdef_start_hdlr(void *dispr, void *priv,
struct phl_msg *msg)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
struct phl_info_t *phl = (struct phl_info_t *)priv;
struct rtw_phl_evt_ops *ops = &phl->phl_com->evt_ops;
struct chg_opch_param *ch_param = NULL;
struct rtw_wifi_role_t *wrole = NULL;
bool (*core_issue_null)(void *, u8, u8, bool, u8) = NULL;
u8 *cmd = NULL;
u32 cmd_len;
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_GENERAL) {
ret = MDL_RET_IGNORE;
goto exit;
}
if (phl_cmd_get_cur_cmdinfo(phl, msg->band_idx, msg, &cmd, &cmd_len)
!= RTW_PHL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Fail to get cmd info \n",
__func__);
goto exit;
}
ch_param = (struct chg_opch_param *)cmd;
wrole = ch_param->wrole;
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: wrole->id(%d)\n",
__func__, wrole->id);
/* Handle mr offchan before switching channel */
/* If the new pri-ch is as same as old pri-ch, offch is unnecessary. */
if (ch_param->new_chdef.chan == ch_param->ori_chdef.chan) {
ret = MDL_RET_SUCCESS;
goto exit;
}
if (ops->issue_null_data) {
core_issue_null = ops->issue_null_data;
} else {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Ops issue_null_data is NULL\n",
__func__);
}
if (RTW_PHL_STATUS_SUCCESS != phl_mr_offch_hdl(phl,
wrole,
ch_param->rlink,
true,
phl->phl_com->drv_priv,
MSG_MDL_ID_FIELD(msg->msg_id),
core_issue_null)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_, "%s: Fail to offch\n",
__func__);
goto exit;
}
ret = MDL_RET_SUCCESS;
exit:
return ret;
}
static enum phl_mdl_ret_code
_mrc_module_msg_pre_hdlr(void *dispr, void *priv, struct phl_msg *msg)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
struct phl_info_t *phl = (struct phl_info_t *)priv;
u8 *cmd = NULL;
u32 cmd_len;
switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
case MSG_EVT_CHG_OP_CH_DEF_END:
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_GENERAL) {
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: MSG_EVT_CHG_OP_CH_DEF_END\n",
__FUNCTION__);
if (RTW_PHL_STATUS_SUCCESS != phl_cmd_get_cur_cmdinfo(phl,
msg->band_idx, msg, &cmd, &cmd_len)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Fail to get cmd info \n",
__func__);
break;
}
if (RTW_PHL_STATUS_SUCCESS !=
_mrc_module_chg_op_chdef_end_pre_hdlr(cmd)) {
break;
}
ret = MDL_RET_SUCCESS;
break;
default:
PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s: MDL ID(%d), Event ID(%d), Not handle event in pre-phase\n",
__FUNCTION__, MSG_MDL_ID_FIELD(msg->msg_id),
MSG_EVT_ID_FIELD(msg->msg_id));
ret = MDL_RET_IGNORE;
break;
}
if (ret == MDL_RET_FAIL) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_,
"%s: MDL(%d), EVT(%d), handle event failed\n",
__FUNCTION__, MSG_MDL_ID_FIELD(msg->msg_id),
MSG_EVT_ID_FIELD(msg->msg_id));
}
return ret;
}
static enum phl_mdl_ret_code
_mrc_module_msg_post_hdl(void *dispr,
void *priv,
struct phl_msg *msg)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct rtw_wifi_role_t *role = NULL;
struct rtw_chan_def chandef = {0};
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
#if defined(CONFIG_STA_CMD_DISPR) || defined(CONFIG_AP_CMD_DISPR)
struct phl_module_op_info op_info = {0};
#endif
struct rtw_phl_evt_ops *ops = &phl_com->evt_ops;
u8 idx = 0xff, hw_band = 0;
struct rtw_phl_stainfo_t *sta = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
bool (*core_issue_null_data)(void *, u8, u8, bool, u8) = NULL;
u8 *cmd = NULL;
u32 cmd_len;
if (ops->issue_null_data)
core_issue_null_data = ops->issue_null_data;
phl_dispr_get_idx(dispr, &idx);
switch(MSG_EVT_ID_FIELD(msg->msg_id)) {
case MSG_EVT_CHG_OP_CH_DEF_START:
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s: MSG_EVT_CHG_OP_CH_DEF_START\n", __FUNCTION__);
ret = _mrc_module_chg_op_chdef_start_hdlr(dispr, priv, msg);
break;
case MSG_EVT_SCAN_START:
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_SCAN_END:
if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_SCAN){
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_SCAN_END\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
/* use primary link to serve scan request for legacy/MLD */
rlink = &role->rlink[RTW_RLINK_PRIMARY];
hw_band = rlink->hw_band;
if (phl_mr_get_chandef(phl_info,
role,
rlink,
false,
&chandef) !=
RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s phl_mr_get_chandef failed\n", __func__);
break;
}
PHL_DUMP_CHAN_DEF_EX(&chandef);
phl_set_ch_bw(phl_info, hw_band, &chandef, RFK_TYPE_SCAN_BK_OP);
phl_mr_offch_hdl(phl_info,
role,
rlink,
false,
phl_com->drv_priv,
MSG_MDL_ID_FIELD(msg->msg_id),
core_issue_null_data);
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_SWCH_START:
if (MSG_MDL_ID_FIELD(msg->msg_id) == PHL_MDL_GENERAL) {
struct setch_param *ch_param = NULL;
if (phl_cmd_get_cur_cmdinfo(phl_info, idx, msg, &cmd, &cmd_len) ==
RTW_PHL_STATUS_SUCCESS) {
ch_param = (struct setch_param *)cmd;
PHL_INFO("[MRC] GEN_CMD_MDL Switch chan ......\n");
PHL_INFO("[MRC] wrole idx:%d\n", ch_param->wrole->id);
PHL_INFO("[MRC] ch:%d, bw:%d, offset:%d\n",
ch_param->chdef.chan,
ch_param->chdef.bw,
ch_param->chdef.offset);
PHL_INFO("[MRC] rt_type:%d\n", ch_param->rt_type);
PHL_INFO("[MRC] GEN_CMD_MDL Switch chan ......\n");
}
ret = MDL_RET_SUCCESS;
} else {
ret = _phl_mrc_module_swch_start_hdlr(dispr,
priv,
msg);
}
break;
case MSG_EVT_SWCH_DONE:
ret = _phl_mrc_module_swch_done_hdlr(dispr,
priv,
msg);
break;
case MSG_EVT_TSF_SYNC_DONE:
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_GENERAL){
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_TSF_SYNC_DONE\n", __FUNCTION__, idx);
if (phl_cmd_get_cur_cmdinfo(phl_info, msg->band_idx,
msg, &cmd, &cmd_len)
!= RTW_PHL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Fail to get cmd info \n",
__func__);
break;
}
sta = (struct rtw_phl_stainfo_t *)cmd;
if(sta == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: sta is NULL\n", __FUNCTION__);
break;
}
SET_STATUS_FLAG(sta->rlink->status, RLINK_STATUS_TSF_SYNC);
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_TDLS_SYNC:
if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_MRC){
ret = MDL_RET_IGNORE;
break;
}
/*
* MR decides to call mcc enable or not
*/
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_TDLS_SYNC\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->inbuf;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[0].ptr;
if(rlink == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: rlink is NULL\n", __FUNCTION__);
break;
}
if (phl_mr_info_upt(phl_info, rlink) != RTW_PHL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"phl_mr_info_upt failed\n");
break;
}
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_TX_RESUME:
if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_MRC){
ret = MDL_RET_IGNORE;
break;
}
/*
* MR resume the tx of the role in remain chanctx
*/
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_TX_RESUME\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[1].ptr;
if(rlink == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role link is NULL\n", __FUNCTION__);
break;
}
phl_mr_offch_hdl(phl_info,
role,
rlink,
false,
phl_com->drv_priv,
MSG_MDL_ID_FIELD(msg->msg_id),
core_issue_null_data);
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_CONNECT_START:
#ifdef CONFIG_STA_CMD_DISPR
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_ADD_DEL_STA) {
ret = MDL_RET_IGNORE;
break;
}
role = (struct rtw_wifi_role_t *)msg->inbuf;
if(role == NULL) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_CONNECT_START\n",
__FUNCTION__, idx);
rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[0].ptr;
if(rlink == NULL) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role link is NULL\n", __FUNCTION__);
break;
}
hw_band = rlink->hw_band;
#ifdef CONFIG_DBCC_SUPPORT
if (phl_mr_is_trigger_dbcc(phl_info)) {
if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, true) !=
RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
ret = MDL_RET_FAIL;
} else {
ret = MDL_RET_PENDING;
}
} else
#endif /*CONFIG_DBCC_SUPPORT*/
{
if(_phl_mrc_module_connect_start_hdlr(phl_info, role, rlink) !=
RTW_PHL_STATUS_SUCCESS) {
break;
}
rtw_hal_notification(phl_info->hal, MSG_EVT_ID_FIELD(msg->msg_id),
hw_band);
ret = MDL_RET_SUCCESS;
}
#endif
break;
#ifdef CONFIG_DBCC_SUPPORT
case MSG_EVT_DBCC_ENABLE:
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s: MSG_EVT_DBCC_ENABLE\n",
__FUNCTION__);
ret = _phl_mrc_module_dbcc_enable(dispr, priv, msg);
if (ret != MDL_RET_SUCCESS) {
PHL_ERR("MSG_EVT_DBCC_ENABLE failed\n");
_os_warn_on(1);
}
phl_disp_eng_clr_pending_msg(phl_info, msg->band_idx);
break;
#ifdef CONFIG_DBCC_P2P_BG_LISTEN
case MSG_EVT_CONNECT_END_DBCC_EN:
case MSG_EVT_DISCONNECT_END_DBCC_EN:
role = (struct rtw_wifi_role_t *)msg->inbuf;
if(role == NULL) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_CONNECT_END_DBCC_EN\n",
__FUNCTION__, idx);
if (phl_mr_is_trigger_dbcc(phl_info)) {
if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, true) !=
RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
ret = MDL_RET_FAIL;
} else {
ret = MDL_RET_PENDING;
}
} else {
ret = MDL_RET_SUCCESS;
}
break;
#endif /*CONFIG_DBCC_P2P_BG_LISTEN*/
#endif
case MSG_EVT_CONNECT_END:
#ifdef CONFIG_STA_CMD_DISPR
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_ADD_DEL_STA) {
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_CONNECT_END\n", __FUNCTION__, idx);
op_info.op_code = FG_REQ_OP_GET_ROLE;
if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
!= RTW_PHL_STATUS_SUCCESS){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"Query wifi role fail!\n");
break;
}
role = (struct rtw_wifi_role_t *)op_info.outbuf;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
op_info.op_code = FG_REQ_OP_GET_ROLE_LINK;
if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
!= RTW_PHL_STATUS_SUCCESS){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"Query wifi role link fail!\n");
break;
}
rlink = (struct rtw_wifi_role_link_t *)op_info.outbuf;
if(rlink == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role link is NULL\n", __FUNCTION__);
break;
}
hw_band = rlink->hw_band;
if(_phl_mrc_module_connect_end_hdlr(phl_info, role) !=
RTW_PHL_STATUS_SUCCESS) {
break;
}
rtw_hal_notification(phl_info->hal, MSG_EVT_ID_FIELD(msg->msg_id),
hw_band);
#endif
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_DISCONNECT_PREPARE:
#ifdef CONFIG_STA_CMD_DISPR
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_DISCONNECT
) {
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_DISCONNECT_PREPARE\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
if (role == NULL) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
#ifdef CONFIG_TWT
rtw_phl_twt_free_all_twt_by_role(phl_info,
role);
#endif
#endif
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_DISCONNECT:
#ifdef CONFIG_STA_CMD_DISPR
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT &&
MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_DISCONNECT &&
MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_ADD_DEL_STA) {
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_DISCONNECT\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
if(_phl_mrc_module_disconnect_hdlr(phl_info, role) !=
RTW_PHL_STATUS_SUCCESS) {
break;
}
#endif
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_DISCONNECT_END:
case MSG_EVT_AP_STOP_END:
#if defined(CONFIG_STA_CMD_DISPR) || defined(CONFIG_AP_CMD_DISPR)
if ((MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_DISCONNECT) &&
(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_CONNECT) &&
(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_STOP) &&
(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START)) {
ret = MDL_RET_IGNORE;
break;
}
if (MSG_EVT_ID_FIELD(msg->msg_id) == MSG_EVT_DISCONNECT_END) {
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_DISCONNECT_END\n", __FUNCTION__, idx);
} else {
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_AP_STOP_END\n", __FUNCTION__, idx);
#ifdef CONFIG_DIG_TDMA
rtw_hal_notification(phl_info->hal, MSG_EVT_AP_STOP_END, HW_BAND_0);
#endif
}
#ifdef CONFIG_DBCC_SUPPORT
if (phl_mr_is_trigger_dbcc(phl_info)) {
ret = _phl_mrc_module_dbcc_disable(dispr, priv, msg);
if (ret != MDL_RET_SUCCESS)
break;
/* core trx-nss protocol handshake*/
role = (struct rtw_wifi_role_t *)msg->inbuf;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, false) !=
RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
ret = MDL_RET_FAIL;
break;
}
ret = MDL_RET_PENDING;
}else
#endif /*CONFIG_DBCC_SUPPORT*/
{
ret = MDL_RET_SUCCESS;
}
#endif
break;
#ifdef CONFIG_DBCC_SUPPORT
case MSG_EVT_DBCC_DISABLE:
ret = _phl_mrc_module_dbcc_disable(dispr, priv, msg);
if (ret != MDL_RET_SUCCESS) {
PHL_ERR("MSG_EVT_DBCC_DISABLE failed\n");
_os_warn_on(1);
}
phl_disp_eng_clr_pending_msg(phl_info, msg->band_idx);
break;
#endif
case MSG_EVT_AP_START_PREPARE:
#ifdef CONFIG_AP_CMD_DISPR
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START) {
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_AP_START_PREPARE\n", __FUNCTION__, idx);
op_info.op_code = FG_REQ_OP_GET_ROLE;
if (phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
!= RTW_PHL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"Query wifi role fail!\n");
break;
}
role = (struct rtw_wifi_role_t *)op_info.outbuf;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
op_info.op_code = FG_REQ_OP_GET_ROLE_LINK;
if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
!= RTW_PHL_STATUS_SUCCESS){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"Query wifi role link fail!\n");
break;
}
rlink = (struct rtw_wifi_role_link_t *)op_info.outbuf;
if(rlink == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role link is NULL\n", __FUNCTION__);
break;
}
#ifdef CONFIG_DBCC_SUPPORT
if (phl_mr_is_trigger_dbcc(phl_info)) {
if (phl_mr_dbcc_proto_hdl(phl_info, msg->band_idx, role, true) !=
RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s mr dbcc send_msg failed\n", __func__);
ret = MDL_RET_FAIL;
} else {
ret = MDL_RET_PENDING;
}
} else
#endif /*CONFIG_DBCC_SUPPORT*/
{
ret = MDL_RET_SUCCESS;
}
#endif
break;
case MSG_EVT_AP_START:
#ifdef CONFIG_AP_CMD_DISPR
if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START){
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_AP_START\n", __FUNCTION__, idx);
op_info.op_code = FG_REQ_OP_GET_ROLE;
if(phl_disp_eng_query_cur_cmd_info(phl_info, idx, &op_info)
!= RTW_PHL_STATUS_SUCCESS){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"Query wifi role fail!\n");
break;
}
role = (struct rtw_wifi_role_t *)op_info.outbuf;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
if(_phl_mrc_module_ap_started_hdlr(phl_info, role) !=
RTW_PHL_STATUS_SUCCESS) {
break;
}
#endif
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_AP_START_END:
#ifdef CONFIG_AP_CMD_DISPR
if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_START){
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_AP_START_END\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
if(msg->inbuf == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s:AP start status info not found!\n",
__FUNCTION__);
ret = MDL_RET_FAIL;
break;
}
if(*(msg->inbuf) != RTW_PHL_STATUS_SUCCESS){
if(_phl_mrc_module_ap_stop_hdlr(phl_info, role)
!= RTW_PHL_STATUS_SUCCESS) {
break;
}
} else {
#ifdef CONFIG_DIG_TDMA
rtw_hal_notification(phl_info->hal, MSG_EVT_AP_START_END, HW_BAND_0);
#endif
}
#endif
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_AP_STOP:
#ifdef CONFIG_AP_CMD_DISPR
if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_AP_STOP){
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_AP_STOP\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
if(_phl_mrc_module_ap_stop_hdlr(phl_info, role) !=
RTW_PHL_STATUS_SUCCESS) {
break;
}
#endif
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_ECSA_SWITCH_DONE:
#ifdef CONFIG_PHL_ECSA
if(MSG_MDL_ID_FIELD(msg->msg_id) != PHL_FG_MDL_ECSA){
ret = MDL_RET_IGNORE;
break;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s[%d]: MSG_EVT_ECSA_SWITCH_DONE\n", __FUNCTION__, idx);
role = (struct rtw_wifi_role_t *)msg->rsvd[0].ptr;
if(role == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role is NULL\n", __FUNCTION__);
break;
}
rlink = (struct rtw_wifi_role_link_t *)msg->rsvd[1].ptr;
if(rlink == NULL){
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: role link is NULL\n", __FUNCTION__);
break;
}
hw_band = rlink->hw_band;
phl_mr_stop_all_beacon(phl_info, role, hw_band, false);
#endif /* CONFIG_PHL_ECSA */
ret = MDL_RET_SUCCESS;
break;
case MSG_EVT_SER_M5_READY:
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_SER) {
ret = MDL_RET_IGNORE;
break;
}
PHL_INFO("%s: MSG_EVT_SER_M5_READY\n", __func__);
phl_mr_err_recovery(phl_info, MSG_EVT_ID_FIELD(msg->msg_id));
ret = MDL_RET_SUCCESS;
break;
default:
ret = MDL_RET_SUCCESS;
break;
}
if (ret == MDL_RET_FAIL) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_,
"%s: MDL(%d), EVT(%d), handle event failed\n",
__FUNCTION__, MSG_MDL_ID_FIELD(msg->msg_id),
MSG_EVT_ID_FIELD(msg->msg_id));
}
return ret;
}
static enum phl_mdl_ret_code
_phl_mrc_module_msg_hdlr(void *dispr, void *priv, struct phl_msg *msg)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
FUNCIN();
if (IS_MSG_FAIL(msg->msg_id)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: cmd dispatcher notify cmd failure: 0x%x.\n",
__FUNCTION__, msg->msg_id);
FUNCOUT();
return MDL_RET_FAIL;
}
if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
ret = _mrc_module_msg_pre_hdlr(dispr, priv, msg);
} else {
ret = _mrc_module_msg_post_hdl(dispr, priv, msg);
}
FUNCOUT();
return ret;
}
static enum phl_mdl_ret_code
_phl_mrc_module_set_info(void *dispr,
void *priv,
struct phl_module_op_info *info)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
FUNCIN();
FUNCOUT();
ret = MDL_RET_SUCCESS;
return ret;
}
static enum phl_mdl_ret_code
_phl_mrc_module_query_info(void *dispr,
void *priv,
struct phl_module_op_info *info)
{
enum phl_mdl_ret_code ret = MDL_RET_FAIL;
FUNCIN();
FUNCOUT();
ret = MDL_RET_SUCCESS;
return ret;
}
static enum rtw_phl_status
_phl_role_bk_module_init(struct phl_info_t *phl_info)
{
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
struct phl_bk_module_ops *bk_ops = &mr_ctl->bk_ops;
bk_ops->init = _phl_mrc_module_init;
bk_ops->deinit = _phl_mrc_module_deinit;
bk_ops->start = _phl_mrc_module_start;
bk_ops->stop = _phl_mrc_module_stop;
bk_ops->msg_hdlr = _phl_mrc_module_msg_hdlr;
bk_ops->set_info = _phl_mrc_module_set_info;
bk_ops->query_info = _phl_mrc_module_query_info;
return RTW_PHL_STATUS_SUCCESS;
}
#endif /*CONFIG_CMD_DISP*/
/*
* init wifi_role control components
* init band_ctrl
* init bk module
* init wifi_role[]
*/
enum rtw_phl_status
phl_mr_ctrl_init(struct phl_info_t *phl_info)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
void *drv = phl_to_drvpriv(phl_info);
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
u8 ridx = MAX_WIFI_ROLE_NUMBER;
struct rtw_wifi_role_link_t *rlink;
u8 lidx;
struct rtw_wifi_role_t *role = NULL;
enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
mr_ctl->hal_com = rtw_hal_get_halcom(phl_info->hal);
if (mr_ctl->hal_com == NULL) {
PHL_ERR("%s mr_ctl->hal_com is NULL\n", __func__);
_os_warn_on(1);
return RTW_PHL_STATUS_FAILURE;
}
_os_spinlock_init(drv, &(mr_ctl->lock));
mr_ctl->is_db = false;
_phl_band_ctrl_init(phl_info);
#ifdef CONFIG_CMD_DISP
_phl_role_bk_module_init(phl_info);
#endif
_os_mem_set(phl_to_drvpriv(phl_info), phl_com->wifi_roles,
0, sizeof(*phl_com->wifi_roles));
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
role = &(phl_com->wifi_roles[ridx]);
pq_init(drv, &role->assoc_mld_queue);
role->phl_com = phl_com;
role->id = ridx;
role->active = false;
for (lidx = 0; lidx < RTW_RLINK_MAX; lidx++) {
rlink = get_rlink(role, lidx);
pq_init(drv, &rlink->assoc_sta_queue);
rlink->wrole = role;
rlink->id = lidx;
rlink->chanctx = NULL;
}
}
#ifdef CONFIG_MCC_SUPPORT
if (RTW_PHL_STATUS_SUCCESS != (status = rtw_phl_mcc_init(phl_info))) {
PHL_ERR("%s mcc init fail\n", __func__);
/* todo, need to discuss with Georgia*/
}
#endif
return RTW_PHL_STATUS_SUCCESS;
}
static enum rtw_phl_status
_phl_band_ctrl_deinit(struct phl_info_t *phl_info)
{
void *drv = phl_to_drvpriv(phl_info);
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
struct hw_band_ctl_t *band_ctrl;
u8 band_idx = 0;
rtw_phl_mcc_deinit(phl_info);
for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
phl_chanctx_free(phl_info, band_ctrl);
_os_spinlock_free(drv, &(band_ctrl->lock));
pq_deinit(drv , &band_ctrl->chan_ctx_queue);
}
return RTW_PHL_STATUS_SUCCESS;
}
enum rtw_phl_status
phl_mr_ctrl_deinit(struct phl_info_t *phl_info)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
u8 ridx = MAX_WIFI_ROLE_NUMBER;
struct rtw_wifi_role_t *role;
void *drv = phl_to_drvpriv(phl_info);
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct rtw_wifi_role_link_t *rlink;
u8 lidx;
_os_spinlock_free(drv, &(mr_ctl->lock));
_phl_band_ctrl_deinit(phl_info);
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
role = &(phl_com->wifi_roles[ridx]);
pq_deinit(drv, &role->assoc_mld_queue);
for (lidx = 0; lidx < RTW_RLINK_MAX; lidx++) {
rlink = get_rlink(role, lidx);
pq_deinit(drv, &rlink->assoc_sta_queue);
}
}
return RTW_PHL_STATUS_SUCCESS;
}
enum rtw_phl_status
phl_mr_chandef_sync(struct phl_info_t *phl_info, struct hw_band_ctl_t *band_ctrl,
struct rtw_chan_ctx *chanctx, struct rtw_chan_def *chandef)
{
void *drv = phl_to_drvpriv(phl_info);
u8 ridx;
u8 role_num = 0;
enum band_type band_ret = BAND_MAX;
u8 ch_ret = 0;
enum channel_width bw_ret = CHANNEL_WIDTH_20;
enum chan_offset offset_ret = CHAN_OFFSET_NO_EXT;
struct rtw_wifi_role_t *wrole;
enum rtw_phl_status phl_sts = RTW_PHL_STATUS_FAILURE;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
if (!chanctx) {
PHL_ERR("%s failed, chanctx == NULL\n", __func__);
goto _exit;
}
if (!chandef) {
PHL_ERR("%s failed, chandef == NULL\n", __func__);
goto _exit;
}
_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (chanctx->role_map & BIT(ridx)) {
wrole = phl_get_wrole_by_ridx(phl_info, ridx);
if (wrole == NULL) {
PHL_ERR("ridx :%d wrole == NULL\n", ridx);
_os_warn_on(1);
continue;
}
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
if (rlink->hw_band == band_ctrl->id)
break;
}
if (role_num == 0) {
band_ret = rlink->chandef.band;
ch_ret = rlink->chandef.chan;
bw_ret = rlink->chandef.bw;
offset_ret = rlink->chandef.offset;
role_num++;
continue;
}
if (band_ret != rlink->chandef.band) {
PHL_ERR("band_ret(%d) != ridx(%d)-band_ret(%d)\n",
band_ret, ridx, rlink->chandef.band);
_os_warn_on(1);
role_num = 0;
break;
}
if (ch_ret != rlink->chandef.chan) {
PHL_ERR("ch_ret(%d) != ridx(%d)-chan(%d)\n",
ch_ret, ridx, rlink->chandef.chan);
_os_warn_on(1);
role_num = 0;
break;
}
if (bw_ret < rlink->chandef.bw) {
bw_ret = rlink->chandef.bw;
offset_ret = rlink->chandef.offset;
} else if (bw_ret == rlink->chandef.bw && offset_ret != rlink->chandef.offset) {
role_num = 0;
break;
}
role_num++;
}
}
_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
if (role_num == 0) {
PHL_ERR("%s role_num=0\n", __func__);
_os_warn_on(!role_num);
goto _exit;
}
PHL_INFO("%s org_chctx - band:%d, chan:%d, bw:%d, offset:%d\n",
__func__, chandef->band, chandef->chan, chandef->bw, chandef->offset);
PHL_INFO("%s mi_upt - band:%d, chan:%d, bw:%d, offset:%d\n",
__func__, band_ret, ch_ret, bw_ret, offset_ret);
chandef->band = band_ret;
chandef->chan = ch_ret;
chandef->bw = bw_ret;
chandef->offset = offset_ret;
phl_sts = RTW_PHL_STATUS_SUCCESS;
_exit:
return phl_sts;
}
/*
* MR change chctx from wrole->chdef to new chdef
* @wrole: specific role, and we can get original chdef.
* @new_chan: new chdef
* @chctx_result: The final ch ctx after change new chdef to MR.
* ex: In the scc case, it will be the group chdef.
*/
enum rtw_phl_status
phl_mr_chandef_chg(struct phl_info_t *phl,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink,
struct rtw_chan_def *new_chan,
struct rtw_chan_def *chctx_result)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct rtw_chan_def chan_def = {0};
struct rtw_mr_chctx_info mr_cc_info = {0};
void *drv = phl_to_drvpriv(phl);
u8 chanctx_num = 0;
chanctx_num = (u8)rtw_phl_chanctx_del(phl, wrole, rlink, &chan_def);
_os_mem_cpy(drv, &chan_def, new_chan, sizeof(struct rtw_chan_def));
if (rtw_phl_chanctx_add((void *)phl, wrole, rlink, &chan_def, &mr_cc_info)) {
_os_mem_cpy(drv, chctx_result, &chan_def,
sizeof(struct rtw_chan_def));
psts = RTW_PHL_STATUS_SUCCESS;
goto exit;
}
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Add new chandef fail, something wrong!\n",
__FUNCTION__);
/* Error handle: Recover the chctx */
_os_mem_cpy(drv, &chan_def, &rlink->chandef,
sizeof(struct rtw_chan_def));
if (!rtw_phl_chanctx_add((void *)phl, wrole, rlink, &chan_def, &mr_cc_info)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Error handle failed for recovery!\n",
__FUNCTION__);
goto exit;
}
exit:
return psts;
}
enum rtw_phl_status
phl_mr_chandef_upt(struct phl_info_t *phl_info,
struct hw_band_ctl_t *band_ctrl, struct rtw_chan_ctx *chanctx)
{
enum rtw_phl_status phl_sts = RTW_PHL_STATUS_FAILURE;
if (!chanctx) {
PHL_ERR("%s chanctx == NULL\n", __func__);
goto _exit;
}
phl_sts = phl_mr_chandef_sync(phl_info, band_ctrl, chanctx, &chanctx->chan_def);
if (phl_sts != RTW_PHL_STATUS_SUCCESS)
PHL_ERR("%s phl_mr_sync_chandef failed\n", __func__);
_exit:
return phl_sts;
}
enum rtw_phl_status
rtw_phl_mr_upt_chandef(void *phl,
struct rtw_wifi_role_link_t *rlink)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
enum rtw_phl_status phl_sts = RTW_PHL_STATUS_FAILURE;
if (!rlink->chanctx) {
PHL_ERR("%s failed - rlink->chanctx == NULL\n", __func__);
goto _exit;
}
phl_sts = phl_mr_chandef_upt(phl_info, band_ctrl, rlink->chanctx);
if (phl_sts != RTW_PHL_STATUS_SUCCESS)
PHL_ERR("%s phl_mr_chandef_upt failed\n", __func__);
_exit:
return phl_sts;
}
int phl_mr_get_chandef_by_band(struct phl_info_t *phl_info,
enum phl_band_idx band_idx,
struct rtw_chan_def *chandef)
{
void *drv = phl_to_drvpriv(phl_info);
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
struct phl_queue *chan_ctx_queue = &band_ctrl->chan_ctx_queue;
struct rtw_chan_ctx *chanctx = NULL;
int chctx_num = 0;
u8 chctx_role_num = 0;
if (!chandef) {
PHL_ERR("%s failed - chandef == NULL\n", __func__);
return chctx_num;
}
/*init chandef*/
chandef->chan = 0;
chctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
if (chctx_num == 0) {
PHL_DBG("%s band:%d chctx_num(%d)\n", __func__, band_idx, chctx_num);
}
else if (chctx_num == 1) {/*SWR or SCC*/
_os_spinlock(drv, &chan_ctx_queue->lock, _bh, NULL);
if (list_empty(&chan_ctx_queue->queue)) {
PHL_ERR("%s chan_ctx_queue->queue is empty\n", __func__);
_os_warn_on(1);
}
chanctx = list_first_entry(&chan_ctx_queue->queue,
struct rtw_chan_ctx, list);
chctx_role_num = phl_chanctx_get_rnum(phl_info, chan_ctx_queue, chanctx);
if (chctx_role_num == 0) {
PHL_ERR("%s-%d chctx_role_num == 0\n", __FUNCTION__, __LINE__);
chctx_num = 0;
_os_warn_on(1);
}
/*chctx_role_num == 1*/
_os_mem_cpy(drv, chandef, &chanctx->chan_def,
sizeof(struct rtw_chan_def));
_os_spinunlock(drv, &chan_ctx_queue->lock, _bh, NULL);
}
else if (chctx_num == 2) {/*MCC*/
PHL_ERR("%s band:%d chctx_num(%d) is not support yet\n",
__func__, band_idx, chctx_num);
}
else {
PHL_ERR("%s band:%d chctx_num(%d) is invalid\n",
__func__, band_idx, chctx_num);
_os_warn_on(1);
}
return chctx_num;
}
int rtw_phl_mr_get_chandef_by_hwband(void *phl,
enum phl_band_idx band_idx,
struct rtw_chan_def *chandef)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return phl_mr_get_chandef_by_band(phl_info, band_idx, chandef);
}
enum rtw_phl_status
phl_mr_get_chandef(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wifi_role,
struct rtw_wifi_role_link_t *rlink,
bool sync,
struct rtw_chan_def *chandef)
{
enum rtw_phl_status phl_sts = RTW_PHL_STATUS_SUCCESS;
void *drv = phl_to_drvpriv(phl_info);
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
u8 hw_band = rlink->hw_band;
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
struct phl_queue *chan_ctx_queue = &band_ctrl->chan_ctx_queue;
struct rtw_chan_ctx *chanctx = NULL;
int chctx_num = 0;
u8 chctx_role_num = 0;
if (!chandef) {
PHL_ERR("%s failed - chandef == NULL\n", __func__);
phl_sts = RTW_PHL_STATUS_FAILURE;
goto _exit;
}
/*init chandef*/
chandef->chan = 0;
if (rlink->chanctx) {
chctx_role_num = phl_chanctx_get_rnum_with_lock(phl_info, chan_ctx_queue, rlink->chanctx);
if (chctx_role_num == 0) {
PHL_ERR("%s-%d chctx_role_num == 0\n", __FUNCTION__, __LINE__);
_os_warn_on(1);
}
if (sync && chctx_role_num >= 2) {
phl_sts = phl_mr_chandef_sync(phl_info, band_ctrl,
rlink->chanctx, chandef);
if (phl_sts != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s phl_mr_chandef_sync failed\n", __func__);
_os_warn_on(1);
}
} else { /*chctx_role_num == 1*/
_os_mem_cpy(drv, chandef, &rlink->chanctx->chan_def,
sizeof(struct rtw_chan_def));
}
} else {
chctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
if (chctx_num == 0) {
_os_mem_cpy(drv, chandef, &rlink->chandef,
sizeof(struct rtw_chan_def));
} else if (chctx_num == 1) {
_os_spinlock(drv, &chan_ctx_queue->lock, _bh, NULL);
if (list_empty(&chan_ctx_queue->queue)) {
PHL_ERR("%s chan_ctx_queue->queue is empty\n", __func__);
_os_warn_on(1);
}
chanctx = list_first_entry(&chan_ctx_queue->queue,
struct rtw_chan_ctx, list);
chctx_role_num = phl_chanctx_get_rnum(phl_info, chan_ctx_queue, chanctx);
if (chctx_role_num == 0) {
PHL_ERR("%s-%d chctx_role_num == 0\n", __FUNCTION__, __LINE__);
_os_warn_on(1);
}
if (sync && chctx_role_num >= 2) {
phl_sts = phl_mr_chandef_sync(phl_info, band_ctrl,
chanctx, chandef);
if (phl_sts != RTW_PHL_STATUS_SUCCESS)
PHL_ERR("%s phl_mr_chandef_sync failed\n", __func__);
} else { /*chctx_role_num == 1*/
_os_mem_cpy(drv, chandef, &chanctx->chan_def,
sizeof(struct rtw_chan_def));
}
_os_spinunlock(drv, &chan_ctx_queue->lock, _bh, NULL);
} else if (chctx_num == 2) { /*MCC*/
} else {
PHL_ERR("%s chctx_num(%d) is invalid\n", __func__, chctx_num);
_os_warn_on(1);
goto _exit;
}
}
_exit:
return phl_sts;
}
struct rtw_wifi_role_t *
phl_mr_get_role_by_bandidx(struct phl_info_t *phl_info, u8 band_idx)
{
struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl_info, band_idx);
struct rtw_wifi_role_t *wrole = NULL;
u8 i;
u8 rnum = 0;
rnum = phl_mr_get_role_num(phl_info, band_ctrl);
if (rnum == 0) {
PHL_ERR("%s B(%d) role number == 0\n", __func__, band_ctrl->id);
goto _exit;
}
for (i = 0; i < MAX_WIFI_ROLE_NUMBER; i++) {
if (band_ctrl->role_map & BIT(i)) {
wrole = phl_get_wrole_by_ridx(phl_info, i);
if (wrole->active == true)
break;
else
wrole = NULL;
}
}
_exit :
if (wrole == NULL) {
PHL_ERR("%s B(%d) cannot get wrole\n", __func__, band_ctrl->id);
/*_os_warn_on(1);*/
}
return wrole;
}
enum rtw_phl_status
rtw_phl_mr_get_chandef(void *phl,
struct rtw_wifi_role_t *wifi_role,
struct rtw_wifi_role_link_t *rlink,
struct rtw_chan_def *chandef)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return phl_mr_get_chandef(phl_info, wifi_role, rlink, false, chandef);
}
int rtw_phl_mr_get_chanctx_num(void *phl,
struct rtw_wifi_role_t *wifi_role,
struct rtw_wifi_role_link_t *rlink)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
u8 band_idx = rlink->hw_band;
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
return phl_mr_get_chanctx_num(phl_info, band_ctrl);
}
enum rtw_phl_status
rtw_phl_mr_rx_filter_opt(void *phl, struct rtw_wifi_role_link_t *rlink)
{
/* Not switch RX filter according to role for AP applications. */
#if !defined(PHL_FEATURE_AP)
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
enum rtw_rx_fltr_opt_mode mode = RX_FLTR_OPT_MODE_STA_NORMAL;
#ifdef CONFIG_MR_SUPPORT
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
if (band_ctrl->cur_info.p2p_device_num >= 1 &&
band_ctrl->cur_info.lsn_discov)
mode = RX_FLTR_OPT_MODE_LSN_DISCOV;
else if (band_ctrl->cur_info.lg_sta_num >= 1)
mode = RX_FLTR_OPT_MODE_STA_LINKING;
else if (band_ctrl->cur_info.ap_num >= 1)
mode = RX_FLTR_OPT_MODE_AP_NORMAL;
else if (band_ctrl->cur_info.ld_sta_num >= 1)
mode = RX_FLTR_OPT_MODE_STA_NORMAL; /* Accpet BSSID matched frames */
else
mode = RX_FLTR_OPT_MODE_STA_NORMAL; /* For STA no link case */
#else
struct rtw_wifi_role_t *wrole = rlink->wrole;
if (rtw_phl_role_is_client_category(wrole) && wrole->mstate == MLME_LINKED)
mode = RX_FLTR_OPT_MODE_STA_NORMAL;
else if (rtw_phl_role_is_client_category(wrole) && wrole->mstate == MLME_LINKING)
mode = RX_FLTR_OPT_MODE_STA_LINKING;
else if (rtw_phl_role_is_ap_category(wrole))
mode = RX_FLTR_OPT_MODE_AP_NORMAL;
else
mode = RX_FLTR_OPT_MODE_STA_NORMAL;/* For STA no link case */
#endif /*CONFIG_MR_SUPPORT*/
rtw_hal_set_rxfltr_opt_by_mode(phl_info->hal, rlink->hw_band, mode);
#endif /* !PHL_AP_FEATURE */
return RTW_PHL_STATUS_SUCCESS;
}
/**
* The decision rule of updating *trgt_cur by comparing with trgt_chk:
* (chk = trgt_chk, cur = *trgt_cur, fnl = final decision of *trgt_cur)
* (D = DROP, H = TO_HOST, W = TO_WLCPU)
*
*
* | cur
* fnl |---------------------------
* | D H W
* -------------------------------------
* | D | D H W
* | |
* chk | H | H H W
* | |
* | W | W W W
*/
static void _phl_mr_rxfltr_target_dcsn(enum rtw_rxfltr_target trgt_chk,
enum rtw_rxfltr_target *trgt_cur)
{
switch (trgt_chk) {
case RXFLTR_TARGET_DROP:
break;
case RXFLTR_TARGET_TO_HOST:
if (*trgt_cur == RXFLTR_TARGET_DROP)
*trgt_cur = RXFLTR_TARGET_TO_HOST;
break;
case RXFLTR_TARGET_TO_WLCPU:
*trgt_cur = RXFLTR_TARGET_TO_WLCPU;
break;
case RXFLTR_TARGET_MAX:
default:
break;
}
}
static void _phl_mr_rxfltr_target_dcsn_ctrl(struct rxfltr_cap_ctrl *cap_chk,
struct rxfltr_cap_to_set_ctrl *cap_cur)
{
u8 i = 0;
for (i = 0; i < RXFLTR_STYPE_CTRL_MAX; i++) {
if (cap_cur->stype[i].set == false)
continue;
_phl_mr_rxfltr_target_dcsn(cap_chk->stype[i].target,
&(cap_cur->stype[i].target));
}
}
static void _phl_mr_rxfltr_target_dcsn_mgnt(struct rxfltr_cap_mgnt *cap_chk,
struct rxfltr_cap_to_set_mgnt *cap_cur)
{
u8 i = 0;
for (i = 0; i < RXFLTR_STYPE_MGNT_MAX; i++) {
if (cap_cur->stype[i].set == false)
continue;
_phl_mr_rxfltr_target_dcsn(cap_chk->stype[i].target,
&(cap_cur->stype[i].target));
}
}
static void _phl_mr_rxfltr_target_dcsn_data(struct rxfltr_cap_data *cap_chk,
struct rxfltr_cap_to_set_data *cap_cur)
{
u8 i = 0;
for (i = 0; i < RXFLTR_STYPE_DATA_MAX; i++) {
if (cap_cur->stype[i].set == false)
continue;
_phl_mr_rxfltr_target_dcsn(cap_chk->stype[i].target,
&(cap_cur->stype[i].target));
}
}
static void _phl_mr_rx_filter_type(struct phl_info_t *phl_info,
struct rtw_wifi_role_link_t *rlink,
struct rxfltr_type_cap_to_set *cap_s)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
u8 role_map = band_ctrl->role_map;
struct rtw_wifi_role_t *wr = NULL;
struct rxfltr_type_cap *cap_rlink = NULL;
u8 ridx = 0, lidx = 0;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
/* only consider allocated role on the same band */
if (!(role_map & BIT(ridx)))
continue;
wr = &(phl_com->wifi_roles[ridx]);
/* exclude inactive role */
if (wr->active == false)
continue;
for (lidx = 0; lidx < wr->rlink_num; lidx++) {
/* only consider rlink on the same hw_band */
if (wr->rlink[lidx].hw_band != rlink->hw_band)
continue;
/* exclude self rlink */
if ((wr->id == rlink->wrole->id) && (wr->rlink[lidx].id == rlink->id))
continue;
cap_rlink = &(wr->rlink[lidx].rxfltr_type_cap);
_phl_mr_rxfltr_target_dcsn_ctrl(&(cap_rlink->rxfltr_ctrl),
&(cap_s->rxfltr_ctrl));
_phl_mr_rxfltr_target_dcsn_mgnt(&(cap_rlink->rxfltr_mgnt),
&(cap_s->rxfltr_mgnt));
_phl_mr_rxfltr_target_dcsn_data(&(cap_rlink->rxfltr_data),
&(cap_s->rxfltr_data));
}
}
}
#define PHL_MR_SET_RXFLTR_STYPE_CTRL(s, t, cr, cs) \
do { \
(cr)->rxfltr_ctrl.stype[s].target = t; \
(cs)->rxfltr_ctrl.stype[s].set = true; \
(cs)->rxfltr_ctrl.stype[s].target = t; \
} while (0)
#define PHL_MR_SET_RXFLTR_STYPE_MGNT(s, t, cr, cs) \
do { \
(cr)->rxfltr_mgnt.stype[s].target = t; \
(cs)->rxfltr_mgnt.stype[s].set = true; \
(cs)->rxfltr_mgnt.stype[s].target = t; \
} while (0)
#define PHL_MR_SET_RXFLTR_STYPE_DATA(s, t, cr, cs) \
do { \
(cr)->rxfltr_data.stype[s].target = t; \
(cs)->rxfltr_data.stype[s].set = true; \
(cs)->rxfltr_data.stype[s].target = t; \
} while (0)
static void _phl_mr_set_rxfltr_cap_by_type(u8 type, u8 target, struct rxfltr_type_cap *cap_rxfltr,
struct rxfltr_type_cap_to_set *cap_rxfltr_s)
{
u8 i = 0;
switch (type) {
case RTW_PHL_PKT_TYPE_CTRL:
for (i = 0; i < RXFLTR_STYPE_CTRL_MAX; i++)
PHL_MR_SET_RXFLTR_STYPE_CTRL(i, target, cap_rxfltr, cap_rxfltr_s);
break;
case RTW_PHL_PKT_TYPE_MGNT:
for (i = 0; i < RXFLTR_STYPE_MGNT_MAX; i++)
PHL_MR_SET_RXFLTR_STYPE_MGNT(i, target, cap_rxfltr, cap_rxfltr_s);
break;
case RTW_PHL_PKT_TYPE_DATA:
for (i = 0; i < RXFLTR_STYPE_DATA_MAX; i++)
PHL_MR_SET_RXFLTR_STYPE_DATA(i, target, cap_rxfltr, cap_rxfltr_s);
break;
}
}
#define PHL_MR_SET_RXFLTR_TYPE_CTRL(t, cr, cs) \
_phl_mr_set_rxfltr_cap_by_type(RTW_PHL_PKT_TYPE_CTRL, t, cr, cs)
#define PHL_MR_SET_RXFLTR_TYPE_MGNT(t, cr ,cs) \
_phl_mr_set_rxfltr_cap_by_type(RTW_PHL_PKT_TYPE_MGNT, t, cr, cs)
#define PHL_MR_SET_RXFLTR_TYPE_DATA(t, cr, cs) \
_phl_mr_set_rxfltr_cap_by_type(RTW_PHL_PKT_TYPE_DATA, t, cr, cs)
enum rtw_phl_status rtw_phl_mr_set_rxfltr_type_by_mode(void *phl, struct rtw_wifi_role_link_t *rlink,
enum rtw_rxfltr_type_mode mode)
{
struct phl_info_t *phl_info = (struct phl_info_t*)phl;
struct rxfltr_type_cap *cap_rlink = NULL;
struct rxfltr_type_cap_to_set cap_rlink_set = {0};
enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE;
cap_rlink = &(rlink->rxfltr_type_cap);
/* set rxfltr type cap of this role link by mode */
switch (mode) {
case RX_FLTR_TYPE_MODE_MONITOR:
PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
PHL_MR_SET_RXFLTR_TYPE_MGNT(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
PHL_MR_SET_RXFLTR_TYPE_DATA(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
break;
case RX_FLTR_TYPE_MODE_ROLE_INIT:
PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
PHL_MR_SET_RXFLTR_TYPE_MGNT(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
PHL_MR_SET_RXFLTR_TYPE_DATA(RXFLTR_TARGET_TO_HOST, cap_rlink, &cap_rlink_set);
break;
case RX_FLTR_TYPE_MODE_STA_CONN:
PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_VHT_HE_NDPA, RXFLTR_TARGET_TO_HOST,
cap_rlink, &cap_rlink_set);
PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_BAR, RXFLTR_TARGET_TO_HOST,
cap_rlink, &cap_rlink_set);
#ifdef RTW_WKARD_RX_FLTR_HE_TF
if (rlink->cap.wmode & WLAN_MD_11AX) {
PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_TRIGGER, RXFLTR_TARGET_TO_HOST,
cap_rlink, &cap_rlink_set);
}
#endif
break;
case RX_FLTR_TYPE_MODE_STA_DIS_CONN:
PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
break;
case RX_FLTR_TYPE_MODE_AP_CONN:
PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_VHT_HE_NDPA, RXFLTR_TARGET_TO_HOST,
cap_rlink, &cap_rlink_set);
PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_BAR, RXFLTR_TARGET_TO_HOST,
cap_rlink, &cap_rlink_set);
PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_PS_POLL, RXFLTR_TARGET_TO_HOST,
cap_rlink, &cap_rlink_set);
break;
case RX_FLTR_TYPE_MODE_AP_DIS_CONN:
if (rlink->assoc_sta_queue.cnt < 2)
PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
break;
#ifdef CONFIG_PHL_CHANNEL_INFO
case RX_FLTR_TYPE_MODE_CHAN_INFO_EN:
PHL_MR_SET_RXFLTR_STYPE_CTRL(RXFLTR_STYPE_ACK, RXFLTR_TARGET_TO_HOST,
cap_rlink, &cap_rlink_set);
break;
case RX_FLTR_TYPE_MODE_CHAN_INFO_DIS:
PHL_MR_SET_RXFLTR_TYPE_CTRL(RXFLTR_TARGET_DROP, cap_rlink, &cap_rlink_set);
break;
#endif
default:
PHL_TRACE(COMP_PHL_RECV, _PHL_ERR_, "%s: does not handle rxfltr mode(%u)\n", __func__, mode);
return RTW_PHL_STATUS_FAILURE;
}
/* jointly decide rxfltr type cap among all active rlinks */
_phl_mr_rx_filter_type(phl_info, rlink, &cap_rlink_set);
/* call HAL API to set rxfltr type cap */
hsts = rtw_hal_set_rxfltr_by_stype_all(phl_info->hal, rlink->hw_band, &cap_rlink_set);
return (hsts == RTW_HAL_STATUS_SUCCESS) ? RTW_PHL_STATUS_SUCCESS : RTW_PHL_STATUS_FAILURE;
}
enum rtw_phl_status phl_mr_tsf_sync(void *phl,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink,
enum role_state state)
{
enum rtw_phl_status ret = RTW_PHL_STATUS_SUCCESS;
#ifdef CONFIG_MR_SUPPORT
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *drv = phl_to_drvpriv(phl_info);
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
enum phl_band_idx band = rlink->hw_band;
struct hw_band_ctl_t *band_ctl = &mr_ctl->band_ctrl[band];
struct rtw_chan_ctx *chanctx = rlink->chanctx;
struct rtw_phl_com_t *phl_com = wrole->phl_com;
struct rtw_wifi_role_t *check_wr = NULL;
struct rtw_wifi_role_t *ld_sta_wr = NULL;
struct rtw_wifi_role_link_t *wrl_sync_from = NULL;
struct rtw_wifi_role_link_t *wrl_sync_to = NULL;
s8 tsf_sync_offset_tu = PHL_MR_TSF_SYNC_BASE_OFFSET; /* unit is TU(1024us) */
u8 tsf_offset_range_rand = 0;
u8 ridx = 0, lidx = 0;
u8 ap_num = band_ctl->cur_info.ap_num;
u8 ld_sta_num = band_ctl->cur_info.ld_sta_num;
int chanctx_num = 0;
tsf_offset_range_rand = _os_random32(drv) % (2 * PHL_MR_TSF_SYNC_OFFSET_RANGE + 1);
if (tsf_offset_range_rand != 0) {
if (tsf_offset_range_rand > PHL_MR_TSF_SYNC_OFFSET_RANGE)
tsf_sync_offset_tu -= (tsf_offset_range_rand - PHL_MR_TSF_SYNC_OFFSET_RANGE);
else
tsf_sync_offset_tu += tsf_offset_range_rand;
}
chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctl);
PHL_INFO("%s:state(%d), ap_num=%d, ld_sta_num=%d, tsf_sync_port=%d,chanctx_num=%d\n",
__func__, state, ap_num, ld_sta_num, band_ctl->tsf_sync_port, chanctx_num);
#ifdef CONFIG_MCC_SUPPORT
if (chanctx_num > 1) {
if (phl_com->dev_cap.mcc_sup == true) {
PHL_INFO("%s: will process MCC, skip tsf sync\n", __func__);
ret = RTW_PHL_STATUS_SUCCESS;
goto exit;
} else {
PHL_ERR("%s: chanctx_num(%d) > 1, check chanctx\n", __func__, chanctx_num);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
}
#endif
switch (state) {
case PHL_ROLE_MSTS_STA_CONN_END:
if (chanctx == NULL) {
PHL_WARN("%s: state%d wifi role (id=%d) role link (id=%d) chanctx=NULL\n", __func__, state, wrole->id, rlink->id);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
/* SoftAP already started, and no tsf sync before */
if (ap_num >= 1 && band_ctl->tsf_sync_port == HW_PORT_MAX) {
/* tsf sync for all softap */
wrl_sync_from = rlink;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (chanctx->role_map & BIT(ridx)) {
check_wr = &phl_com->wifi_roles[ridx];
/* Get role link from another role within the same chanctx */
for (lidx = 0; lidx < check_wr->rlink_num; lidx++) {
wrl_sync_to = get_rlink(check_wr, lidx);
if (wrl_sync_to->hw_band == band)
break;
}
if (lidx == check_wr->rlink_num) {
PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
if (wrole != check_wr) {
switch (check_wr->type) {
case PHL_RTYPE_AP:
case PHL_RTYPE_VAP:
case PHL_RTYPE_P2P_GO:
case PHL_RTYPE_MESH:
if (rtw_hal_tsf_sync(phl_info->hal, wrl_sync_from->hw_port,
wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
ret = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) success\n",
__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
wrole->id, wrl_sync_from->id, wrl_sync_from->hw_port);
} else {
ret = RTW_PHL_STATUS_FAILURE;
PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) fail\n",
__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
wrole->id, wrl_sync_from->id, wrl_sync_from->hw_port);
break;
}
break;
default :
break;
}
}
}
}
if (ret == RTW_PHL_STATUS_SUCCESS)
band_ctl->tsf_sync_port = wrl_sync_from->hw_port;
else
band_ctl->tsf_sync_port = HW_PORT_MAX;
}
break;
case PHL_ROLE_MSTS_STA_DIS_CONN:
/* if TSF sync do not enable, skip disable flow */
if (band_ctl->tsf_sync_port == HW_PORT_MAX) {
ret = RTW_PHL_STATUS_SUCCESS;
goto exit;
}
if (chanctx == NULL) {
PHL_WARN("%s: state(%d) wifi role (id=%d) role link (id=%d) chanctx=NULL\n",
__func__, state, wrole->id, rlink->id);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
/* if disconnected STA is sync port and SoftAP exists,
find new sync port */
if (rlink->hw_port == band_ctl->tsf_sync_port &&
ap_num >= 1 && ld_sta_num > 0) {
/* find linked sta */
ld_sta_wr = _search_ld_sta_wrole(wrole, rlink, true);
if (ld_sta_wr) {
/* Get role link from ld_sta_wr within the same hw band */
for (lidx = 0; lidx < ld_sta_wr->rlink_num; lidx++) {
wrl_sync_from = get_rlink(ld_sta_wr, lidx);
if (wrl_sync_from->hw_band == band)
break;
}
if (lidx == ld_sta_wr->rlink_num) {
PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
/* re-sync tsf for all softap */
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (chanctx->role_map & BIT(ridx)) {
check_wr = &phl_com->wifi_roles[ridx];
check_wr = &phl_com->wifi_roles[ridx];
/* Get role link from another role within the same chanctx */
for (lidx = 0; lidx < check_wr->rlink_num; lidx++) {
wrl_sync_to = get_rlink(check_wr, lidx);
if (wrl_sync_to->hw_band == band)
break;
}
if (lidx == check_wr->rlink_num) {
PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
if (ld_sta_wr != check_wr) {
switch (check_wr->type) {
case PHL_RTYPE_AP:
case PHL_RTYPE_VAP:
case PHL_RTYPE_P2P_GO:
case PHL_RTYPE_MESH:
if (rtw_hal_tsf_sync(phl_info->hal, wrl_sync_from->hw_port,
wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
ret = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) success\n",
__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
} else {
ret = RTW_PHL_STATUS_FAILURE;
PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) fail\n",
__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
break;
}
break;
default :
break;
}
}
}
}
if (ret == RTW_PHL_STATUS_SUCCESS)
band_ctl->tsf_sync_port = wrl_sync_from->hw_port;
else
band_ctl->tsf_sync_port = HW_PORT_MAX;
}
}
/* if disconnected STA is sync port and no other linked sta exist,
disable sofap tsf sync */
if (rlink->hw_port == band_ctl->tsf_sync_port && ld_sta_num == 0) {
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (chanctx->role_map & BIT(ridx)){
check_wr = &phl_com->wifi_roles[ridx];
/* Get role link from another role within the same chanctx */
for (lidx = 0; lidx < check_wr->rlink_num; lidx++) {
wrl_sync_to = get_rlink(check_wr, lidx);
if (wrl_sync_to->hw_band == band)
break;
}
if (lidx == check_wr->rlink_num) {
PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
if (wrole != check_wr) {
switch (check_wr->type) {
case PHL_RTYPE_AP:
case PHL_RTYPE_VAP:
case PHL_RTYPE_P2P_GO:
case PHL_RTYPE_MESH:
if (check_wr->mstate == MLME_LINKED) {
if (rtw_hal_tsf_sync(phl_info->hal, band_ctl->tsf_sync_port,
wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_DIS_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
ret = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole (port:%d) success\n",
__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
band_ctl->tsf_sync_port);
} else {
ret = RTW_PHL_STATUS_FAILURE;
PHL_ERR("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole:(port:%d) fail\n",
__func__, check_wr->id, wrl_sync_to->id, wrl_sync_to->hw_port,
band_ctl->tsf_sync_port);
break;
}
}
break;
default :
break;
}
}
}
}
if (ret == RTW_PHL_STATUS_SUCCESS)
band_ctl->tsf_sync_port = HW_PORT_MAX;
}
break;
case PHL_ROLE_MSTS_AP_START:
if (chanctx == NULL) {
PHL_WARN("%s: state%d wifi role (id=%d) rlink (id=%d)chanctx=NULL\n", __func__, state, wrole->id, rlink->id);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
/* no linked sta, don't enable tsf sync */
if (ld_sta_num == 0) {
ret = RTW_PHL_STATUS_SUCCESS;
goto exit;
}
/* New softAP start, and no tsf sync before, find sync port */
if (band_ctl->tsf_sync_port == HW_PORT_MAX) {
wrl_sync_to = rlink;
ld_sta_wr = _search_ld_sta_wrole(wrole, rlink, true);
if (ld_sta_wr) {
/* Get role link from ld_sta_wr within the same hw band */
for (lidx = 0; lidx < ld_sta_wr->rlink_num; lidx++) {
wrl_sync_from = get_rlink(ld_sta_wr, lidx);
if (wrl_sync_from->hw_band == band)
break;
}
if (lidx == ld_sta_wr->rlink_num) {
PHL_ERR("%s Can not get target link in the same hw band in another role!\n", __func__);
ret = RTW_PHL_STATUS_FAILURE;
goto exit;
}
if (rtw_hal_tsf_sync(phl_info->hal, wrl_sync_from->hw_port,
wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
band_ctl->tsf_sync_port = wrl_sync_from->hw_port;
ret = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) success\n",
__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
} else {
ret = RTW_PHL_STATUS_FAILURE;
PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole-rlink:%d-%d(port:%d) fail\n",
__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
ld_sta_wr->id, wrl_sync_from->id, wrl_sync_from->hw_port);
}
}
} else if (band_ctl->tsf_sync_port != HW_PORT_MAX) {
/* New softAP start, enable tsf sync before, follow original sync port */
wrl_sync_to = rlink;
if (rtw_hal_tsf_sync(phl_info->hal, band_ctl->tsf_sync_port,
wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_EN_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
ret = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) success\n",
__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
band_ctl->tsf_sync_port);
} else {
ret = RTW_PHL_STATUS_FAILURE;
PHL_ERR("%s, enable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) fail\n",
__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
band_ctl->tsf_sync_port);
}
}
break;
case PHL_ROLE_MSTS_AP_STOP:
/* if TSF sync do not enable, skip disable flow */
if (band_ctl->tsf_sync_port == HW_PORT_MAX) {
ret = RTW_PHL_STATUS_SUCCESS;
goto exit;
}
wrl_sync_to = rlink;
if (rtw_hal_tsf_sync(phl_info->hal, band_ctl->tsf_sync_port,
wrl_sync_to->hw_port, band, tsf_sync_offset_tu, HAL_TSF_DIS_SYNC_AUTO) == RTW_HAL_STATUS_SUCCESS) {
ret = RTW_PHL_STATUS_SUCCESS;
PHL_INFO("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) success\n",
__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
band_ctl->tsf_sync_port);
} else {
ret = RTW_PHL_STATUS_FAILURE;
PHL_ERR("%s, disable wrole-rlink:%d-%d(port:%d) sync from wrole(port:%d) fail\n",
__func__, wrole->id, wrl_sync_to->id, wrl_sync_to->hw_port,
band_ctl->tsf_sync_port);
}
if (ap_num == 0)
band_ctl->tsf_sync_port = HW_PORT_MAX;
break;
default:
PHL_ERR("%s unsupport state(%d)\n", __func__, state);
ret = RTW_PHL_STATUS_FAILURE;
break;
}
exit:
#endif
return ret;
}
#ifdef CONFIG_FSM
enum rtw_phl_status
rtw_phl_mr_offch_hdl(void *phl,
struct rtw_wifi_role_t *wrole,
bool off_ch,
void *obj_priv,
bool (*issue_null_data)(void *priv, u8 ridx, bool ps),
struct rtw_chan_def *chandef)
{
return RTW_PHL_STATUS_SUCCESS;
}
#endif
void phl_mr_stop_all_beacon(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole,
u8 band_idx,
bool stop)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
u8 role_map = band_ctrl->role_map;
struct rtw_wifi_role_t *wr = NULL;
u8 ridx;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (role_map & BIT(ridx)) {
wr = &(phl_com->wifi_roles[ridx]);
if (rtw_phl_role_is_ap_category(wr) ||
(wr->type == PHL_RTYPE_MESH)){
for (idx = 0; idx < wr->rlink_num; idx++) {
rlink = get_rlink(wr, idx);
if (rlink->hw_band != band_idx)
continue;
rtw_hal_beacon_stop(phl_info->hal, rlink,
RLINK_BCN_STOP_RSON_DEFAULT, stop);
}
}
}
}
}
#ifdef DBG_PHL_MR
enum rtw_phl_status
phl_mr_info_dbg(struct phl_info_t *phl_info)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
u8 ridx = MAX_WIFI_ROLE_NUMBER;
u8 bidx = 0;
int chanctx_num = 0;
struct rtw_wifi_role_t *role = NULL;
struct hw_band_ctl_t *band_ctrl = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 idx = 0;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
role = &(phl_com->wifi_roles[ridx]);
for (idx = 0; idx < role->rlink_num; idx++) {
rlink = get_rlink(role, idx);
if (rlink->assoc_sta_queue.cnt) {
PHL_DUMP_STACTRL_EX(phl_info);
PHL_ERR("role_idx:%d link_idx: %d assoc_sta_queue(%d) not empty!\n",
ridx, idx, rlink->assoc_sta_queue.cnt);
_os_warn_on(1);
}
}
}
for (bidx = 0; bidx < MAX_BAND_NUM; bidx++) {
band_ctrl = &(mr_ctl->band_ctrl[bidx]);
chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
if (chanctx_num)
PHL_ERR("band_idx:%d chanctx_num(%d) not empty!\n", bidx, chanctx_num);
}
return RTW_PHL_STATUS_SUCCESS;
}
#endif
enum rtw_phl_status
phl_mr_info_upt(struct phl_info_t *phl_info, struct rtw_wifi_role_link_t *rlink)
{
void *drv = phl_to_drvpriv(phl_info);
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
u8 role_map = band_ctrl->role_map;
struct rtw_wifi_role_t *wr = NULL;
u8 ridx;
_os_mem_set(drv, &band_ctrl->cur_info, 0, sizeof(struct mr_info));
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (!(role_map & BIT(ridx)))
continue;
wr = &(phl_com->wifi_roles[ridx]);
switch (wr->type) {
case PHL_RTYPE_STATION:
case PHL_RTYPE_P2P_GC:
case PHL_RTYPE_P2P_DEVICE:
case PHL_RTYPE_TDLS:
band_ctrl->cur_info.sta_num++;
if (wr->mstate == MLME_LINKED)
band_ctrl->cur_info.ld_sta_num++;
if (wr->mstate == MLME_LINKING)
band_ctrl->cur_info.lg_sta_num++;
if (wr->type == PHL_RTYPE_P2P_GC)
band_ctrl->cur_info.p2p_gc_num++;
if (wr->type == PHL_RTYPE_P2P_DEVICE) {
band_ctrl->cur_info.p2p_device_num++;
if (TEST_STATUS_FLAG(wr->status, WR_STATUS_LSN_DISCOV))
band_ctrl->cur_info.lsn_discov = true;
}
#ifdef CONFIG_PHL_TDLS
if (wr->type == PHL_RTYPE_TDLS)
band_ctrl->cur_info.ld_tdls_num++;
#endif
break;
case PHL_RTYPE_AP:
case PHL_RTYPE_VAP:
case PHL_RTYPE_P2P_GO:
case PHL_RTYPE_MESH:
if (wr->mstate == MLME_LINKED)
band_ctrl->cur_info.ap_num++;
if (wr->assoc_mld_queue.cnt >= 2)
band_ctrl->cur_info.ld_ap_num++;
if (wr->type == PHL_RTYPE_P2P_GO)
band_ctrl->cur_info.p2p_go_num++;
break;
case PHL_RTYPE_MONITOR:
band_ctrl->cur_info.monitor_num++;
break;
case PHL_RTYPE_ADHOC:
case PHL_RTYPE_ADHOC_MASTER:
case PHL_RTYPE_NAN:
default :
break;
}
}
if(band_ctrl->op_mode == MR_OP_SCC ||
band_ctrl->op_mode == MR_OP_MCC){
if(band_ctrl->cur_info.ld_sta_num && band_ctrl->cur_info.ap_num)
band_ctrl->op_type = MR_OP_TYPE_STATION_AP;
else if(band_ctrl->cur_info.ld_sta_num)
band_ctrl->op_type = MR_OP_TYPE_STATION_ONLY;
else
band_ctrl->op_type = MR_OP_TYPE_STATION_AP;
}
else{
band_ctrl->op_type = MR_OP_TYPE_NONE;
}
/*dump mr_info*/
PHL_INFO("%s sta_num:%d, ld_sta_num:%d, lg_sta_num:%d\n",
__func__, band_ctrl->cur_info.sta_num,
band_ctrl->cur_info.ld_sta_num, band_ctrl->cur_info.lg_sta_num);
#ifdef CONFIG_PHL_TDLS
PHL_INFO("%s ld_tdls_num:%d\n", __func__, band_ctrl->cur_info.ld_tdls_num);
#endif
PHL_INFO("%s ap_num:%d, ld_ap_num:%d\n",
__func__, band_ctrl->cur_info.ap_num, band_ctrl->cur_info.ld_ap_num);
PHL_INFO("%s p2p_device_num:%d, lsn_discov:%d\n",
__func__, band_ctrl->cur_info.p2p_device_num,
band_ctrl->cur_info.lsn_discov);
PHL_INFO("%s op mode:%d op type:%d\n",
__func__, band_ctrl->op_mode, band_ctrl->op_type);
return RTW_PHL_STATUS_SUCCESS;
}
enum rtw_phl_status phl_mr_watchdog(struct phl_info_t *phl_info)
{
enum rtw_phl_status psts = RTW_PHL_STATUS_SUCCESS;
#if defined(CONFIG_MR_SUPPORT) && defined(CONFIG_MCC_SUPPORT)
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
u8 band_idx = 0;
int chanctx_num = 0;
struct hw_band_ctl_t *band_ctrl = NULL;
#if 0
struct rtw_chan_ctx *chanctx = NULL;
void *drv = phl_to_drvpriv(phl_info);
struct rtw_wifi_role_t *wr = NULL;
#endif
for (band_idx = 0; band_idx < MAX_BAND_NUM; band_idx++) {
band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
chanctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
if (chanctx_num == 0)
continue;
#if 0
_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (chanctx->role_map & BIT(ridx)) {
wr = &phl_com->wifi_roles[ridx];
if(wr->type == PHL_RTYPE_STATION) {
/*Sounding check*/
/*phl_snd_watchdog(phl_info, wr);*/
}
}
}
}
_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
#endif
if (chanctx_num == 2)
rtw_phl_mcc_watchdog(phl_info, band_idx);
}
#endif /*CONFIG_MCC_SUPPORT*/
return psts;
}
static inline u8
__phl_mr_process(struct rtw_wifi_role_t *wrole,
u8 role_map, bool exclude_self, void *data,
u8(*ops_func)(struct rtw_wifi_role_t *wrole, void *data))
{
u8 ridx = 0;
u8 ret = 0;
struct rtw_phl_com_t *phl_com = wrole->phl_com;
struct rtw_wifi_role_t *wr = NULL;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (role_map & BIT(ridx)) {
wr = &phl_com->wifi_roles[ridx];
_os_warn_on(!wr->active);
if ((exclude_self) && (wr == wrole))
continue;
if (ops_func)
if (true == ops_func(wr, data))
ret++;
}
}
return ret;
}
static u8 _phl_mr_process_by_mrc(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole, bool exclude_self, void *data,
u8(*ops_func)(struct rtw_wifi_role_t *wrole, void *data))
{
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(wrole->phl_com);
return __phl_mr_process(wrole, mr_ctl->role_map, exclude_self, data, ops_func);
}
static u8 _phl_mr_process_by_band(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole,
enum phl_band_idx band_idx,
bool exclude_self,
void *data,
u8(*ops_func)(struct rtw_wifi_role_t *wrole,
void *data))
{
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
return __phl_mr_process(wrole, band_ctrl->role_map, exclude_self, data, ops_func);
}
static u8 _phl_mr_process_by_chctx(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink,
bool exclude_self,
void *data,
u8(*ops_func)(struct rtw_wifi_role_t *wrole, void *data))
{
struct rtw_chan_ctx *chanctx = rlink->chanctx;
if (!chanctx)
return 0;
return __phl_mr_process(wrole, chanctx->role_map, exclude_self, data, ops_func);
}
static u8 _phl_mr_dump_mac_addr(struct rtw_wifi_role_t *wrole, void *data)
{
PHL_INFO("RIDX:%d - MAC-Addr:%02x-%02x-%02x-%02x-%02x-%02x\n",
wrole->id, wrole->mac_addr[0], wrole->mac_addr[1], wrole->mac_addr[2],
wrole->mac_addr[3], wrole->mac_addr[4], wrole->mac_addr[5]);
return true;
}
u8 rtw_phl_mr_dump_mac_addr(void *phl,
struct rtw_wifi_role_t *wifi_role)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return _phl_mr_process_by_mrc(phl_info, wifi_role, false, NULL, _phl_mr_dump_mac_addr);
}
u8 rtw_phl_mr_buddy_dump_mac_addr(void *phl,
struct rtw_wifi_role_t *wifi_role)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
return _phl_mr_process_by_mrc(phl_info, wifi_role, true, NULL, _phl_mr_dump_mac_addr);
}
static inline u8
__phl_mr_process_ex(struct rtw_phl_com_t *phl_com,
u8 role_map, void *data,
u8(*ops_func)(void *drv_priv, u8 wr_idx, void *data))
{
u8 ridx = 0;
u8 ret = 0;
struct rtw_wifi_role_t *wr = NULL;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (role_map & BIT(ridx)) {
wr = &phl_com->wifi_roles[ridx];
_os_warn_on(!wr->active);
if (ops_func)
if (true == ops_func(phl_com->drv_priv, wr->id, data))
ret++;
}
}
return ret;
}
u8 rtw_phl_mr_process_by_band(void *phl,
enum phl_band_idx band_idx, void *data,
u8(*ops_func)(void *drv_priv, u8 wr_idx, void *data))
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_info->phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[band_idx]);
return __phl_mr_process_ex(phl_info->phl_com, band_ctrl->role_map, data, ops_func);
}
bool rtw_phl_mr_query_info(void *phl,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink,
struct mr_query_info *info)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
info->op_mode = band_ctrl->op_mode;
info->op_type = band_ctrl->op_type;
_os_mem_cpy(phl_to_drvpriv(phl_info), &info->cur_info,
&band_ctrl->cur_info, sizeof(struct mr_info));
return true;
}
void rtw_phl_mr_ops_init(void *phl, struct rtw_phl_mr_ops *mr_ops)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
mr_ctl->mr_ops.priv = mr_ops->priv;
#ifdef CONFIG_PHL_P2PPS
mr_ctl->mr_ops.phl_mr_update_noa = mr_ops->phl_mr_update_noa;
#endif /* CONFIG_PHL_P2PPS */
#ifdef CONFIG_MCC_SUPPORT
if (mr_ops->mcc_ops != NULL)
rtw_phl_mcc_init_ops(phl_info, mr_ops->mcc_ops);
#endif
#ifdef CONFIG_DBCC_SUPPORT
mr_ctl->mr_ops.dbcc_protocol_hdl = mr_ops->dbcc_protocol_hdl;
#endif
}
u8 rtw_phl_mr_get_opch_list(void *phl, u8 hw_band,
struct rtw_chan_def *chdef_list, u8 list_size,
struct rtw_wifi_role_link_t *rlink[], u8 rlink_num)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
void *drv = phl_to_drvpriv(phl_info);
struct rtw_chan_ctx *chanctx = NULL;
int ctx_num = 0;
u8 total_op_num = 0, i = 0;
if((chdef_list == NULL) || (list_size == 0)){
PHL_ERR("Parameter Invalid!\n");
goto _exit;
}
ctx_num = phl_mr_get_chanctx_num(phl_info, band_ctrl);
if (ctx_num == 0){
PHL_DBG("ctx_num == 0!\n");
goto _exit;
}
_os_spinlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
phl_list_for_loop(chanctx, struct rtw_chan_ctx, &band_ctrl->chan_ctx_queue.queue, list) {
if(total_op_num >= list_size)
break;
if (rlink_num != 0 && rlink != NULL) {
for (i = 0; i < rlink_num; i++) {
if (rlink[i]->hw_band == hw_band) {
if (rlink[i]->chandef.chan == chanctx->chan_def.chan) {
*(chdef_list + total_op_num) = chanctx->chan_def;
total_op_num++;
break;
}
}
}
} else {
*(chdef_list + total_op_num) = chanctx->chan_def;
total_op_num++;
}
}
_os_spinunlock(drv, &band_ctrl->chan_ctx_queue.lock, _bh, NULL);
_exit:
return total_op_num;
}
enum mr_op_mode
rtw_phl_mr_get_opmode(void *phl,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
return band_ctrl->op_mode;
}
void
phl_mr_check_ecsa(struct phl_info_t *phl_info,
enum phl_band_idx hw_band
)
{
#ifdef CONFIG_PHL_ECSA
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[hw_band]);
u8 role_map = band_ctrl->role_map;
struct rtw_wifi_role_t *wr = NULL, *ap_wr = NULL, *sta_wr = NULL;
u8 ridx;
enum band_type ap_band_type = BAND_ON_24G, sta_band_type = BAND_ON_24G;
enum phl_ecsa_start_reason reason = ECSA_START_UNKNOWN;
u32 delay_start_ms = 0;
#ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
u32 extend_option = 0;
#endif
bool ecsa_allow = false;
struct rtw_phl_ecsa_param param = {0};
void *d = phlcom_to_drvpriv(phl_com);
struct rtw_wifi_role_link_t *rlink = NULL, *sta_rlink = NULL, *ap_rlink = NULL;
if(band_ctrl->op_mode != MR_OP_MCC)
return;
if(band_ctrl->op_type != MR_OP_TYPE_STATION_AP)
return;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (role_map & BIT(ridx)) {
wr = &(phl_com->wifi_roles[ridx]);
if (wr->rlink_num > 1)
continue;
rlink = phl_get_rlink_by_hw_band(wr, hw_band);
switch (wr->type) {
case PHL_RTYPE_STATION:
case PHL_RTYPE_P2P_GC:
case PHL_RTYPE_TDLS:
if (rlink->mstate == MLME_LINKED){
sta_band_type = rlink->chandef.band;
sta_wr = wr;
sta_rlink = rlink;
}
break;
case PHL_RTYPE_AP:
case PHL_RTYPE_VAP:
case PHL_RTYPE_P2P_GO:
case PHL_RTYPE_MESH:
if (rlink->mstate == MLME_LINKED){
ap_band_type = rlink->chandef.band;
ap_wr = wr;
ap_rlink = rlink;
}
break;
case PHL_RTYPE_MONITOR:
case PHL_RTYPE_P2P_DEVICE:
default :
break;
}
}
}
if (!sta_rlink || !ap_rlink)
return;
if(sta_band_type == BAND_ON_24G){
if(ap_band_type == BAND_ON_24G)
reason = ECSA_START_MCC_24G_TO_24G;
else if(ap_band_type == BAND_ON_5G)
reason = ECSA_START_MCC_5G_TO_24G;
else
reason = ECSA_START_UNKNOWN;
}
else if(sta_band_type == BAND_ON_5G){
if(ap_band_type == BAND_ON_24G)
reason = ECSA_START_MCC_24G_TO_5G;
else if(ap_band_type == BAND_ON_5G)
reason = ECSA_START_MCC_5G_TO_5G;
else
reason = ECSA_START_UNKNOWN;
}
else{
reason = ECSA_START_UNKNOWN;
}
if(reason != ECSA_START_UNKNOWN){
ecsa_allow = rtw_phl_ecsa_check_allow(phl_info,
ap_wr,
sta_rlink->chandef,
reason,
#ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
&extend_option,
#endif
&delay_start_ms);
}
if(ecsa_allow){
param.ecsa_type = ECSA_TYPE_AP;
param.count = ECSA_DEFAULT_CHANNEL_SWITCH_COUNT;
param.delay_start_ms = delay_start_ms;
param.flag = 0;
param.mode = CHANNEL_SWITCH_MODE_NORMAL;
param.ch = sta_rlink->chandef.chan;
param.op_class = rtw_phl_get_operating_class(sta_rlink->chandef);
_os_mem_cpy(d, &(param.new_chan_def), &(sta_rlink->chandef),
sizeof(struct rtw_chan_def));
#ifdef CONFIG_PHL_ECSA_EXTEND_OPTION
rtw_phl_ecsa_extend_option_hdlr(extend_option,
ap_rlink,
&param);
#endif
pstatus = rtw_phl_ecsa_start(phl_info,
ap_wr,
ap_rlink,
&param);
if(pstatus == RTW_PHL_STATUS_SUCCESS)
PHL_INFO("%s: ECSA start OK!\n", __FUNCTION__);
else
PHL_INFO("%s: ECSA start fail!\n", __FUNCTION__);
}
#endif /* CONFIG_PHL_ECSA */
}
void
phl_mr_check_ecsa_cancel(struct phl_info_t *phl_info,
struct rtw_wifi_role_t *wrole,
struct rtw_wifi_role_link_t *rlink)
{
#ifdef CONFIG_PHL_ECSA
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com);
struct hw_band_ctl_t *band_ctrl = &(mr_ctl->band_ctrl[rlink->hw_band]);
if(band_ctrl->op_mode != MR_OP_MCC)
return;
if(band_ctrl->op_type != MR_OP_TYPE_STATION_AP)
return;
pstatus = rtw_phl_ecsa_cancel(phl_info, wrole);
if(pstatus == RTW_PHL_STATUS_SUCCESS)
PHL_INFO("%s: ECSA cancel OK!\n", __FUNCTION__);
else
PHL_INFO("%s: ECSA cancel fail!\n", __FUNCTION__);
#endif /* CONFIG_PHL_ECSA */
}
enum rtw_phl_status
phl_mr_err_recovery(struct phl_info_t *phl, enum phl_msg_evt_id eid)
{
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
if (eid == MSG_EVT_SER_M5_READY) {
/* SER L1 DONE event */
rtw_phl_tdmra_recovery(phl, HW_BAND_0);
}
return status;
}
#ifdef CONFIG_DBCC_P2P_BG_LISTEN
struct rtw_wifi_role_link_t *
phl_mr_get_first_rlink_by_band_ex(struct phl_info_t *phl,
enum phl_band_idx band,
bool linked)
{
struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, band);
struct rtw_wifi_role_t *wrole = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 role_map = band_ctrl->role_map;
u8 ridx = 0, idx = 0;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (!(role_map & BIT(ridx)))
continue;
wrole = &phl->phl_com->wifi_roles[ridx];
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
if (linked && rlink->chanctx == NULL)
continue;
if (rlink->hw_band == band) {
PHL_INFO("%s: ridx(%d), rlink[%d]\n", __FUNCTION__,
ridx, idx);
return rlink;
}
}
}
return NULL;
}
#endif
struct rtw_wifi_role_link_t *
phl_mr_get_first_rlink_by_band(struct phl_info_t *phl,
enum phl_band_idx band)
{
struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, band);
struct rtw_wifi_role_t *wrole = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
u8 role_map = band_ctrl->role_map;
u8 ridx = 0, idx = 0;
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (!(role_map & BIT(ridx)))
continue;
wrole = &phl->phl_com->wifi_roles[ridx];
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
if (rlink->chanctx == NULL)
continue;
if (rlink->hw_band == band) {
PHL_INFO("%s: ridx(%d), rlink[%d]\n", __FUNCTION__,
ridx, idx);
return rlink;
}
}
}
return NULL;
}
struct rtw_wifi_role_link_t *
phl_mr_get_rlink_stay_in_cur_chdef(struct phl_info_t *phl,
enum phl_band_idx band)
{
struct hw_band_ctl_t *band_ctrl = get_band_ctrl(phl, band);
struct rtw_wifi_role_t *wrole = NULL;
struct rtw_wifi_role_link_t *rlink = NULL;
struct rtw_chan_def cur_chdef = {0};
u8 role_map = band_ctrl->role_map;
u8 ridx = 0, idx = 0;
rtw_hal_get_cur_chdef(phl->hal, band, &cur_chdef);
for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
if (!(role_map & BIT(ridx)))
continue;
wrole = &phl->phl_com->wifi_roles[ridx];
for (idx = 0; idx < wrole->rlink_num; idx++) {
rlink = get_rlink(wrole, idx);
if (rlink->chanctx == NULL)
continue;
if (rlink->hw_band != band)
continue;
if (rlink->chanctx->chan_def.chan == cur_chdef.chan) {
PHL_INFO("%s: ridx(%d), rlink[%d]\n", __FUNCTION__,
ridx, idx);
return rlink;
}
}
}
return NULL;
}
/* MR coex related code */