/****************************************************************************** * * 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, ¶m); #endif pstatus = rtw_phl_ecsa_start(phl_info, ap_wr, ap_rlink, ¶m); 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 */