/****************************************************************************** * * 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_ROLE_C_ #include "phl_headers.h" static enum rtw_phl_status _phl_alloc_hw_port(struct phl_info_t *phl, struct rtw_wifi_role_link_t *rlink) { struct rtw_phl_com_t *phl_com = phl->phl_com; struct hal_spec_t *hal_spec = phl_get_ic_spec(phl_com); struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); struct hw_band_ctl_t *band_ctrl; u8 max_port_num = hal_spec->port_num; u8 i = max_port_num; band_ctrl = &mr_ctl->band_ctrl[rlink->hw_band]; _os_spinlock(phl_to_drvpriv(phl), &band_ctrl->lock, _bh, NULL); for (i = 0; i < max_port_num; i++) { if (!(band_ctrl->port_map & BIT(i))) { band_ctrl->port_map |= BIT(i); break; } } _os_spinunlock(phl_to_drvpriv(phl), &band_ctrl->lock, _bh, NULL); if (i == max_port_num) { PHL_ERR("%s Can't get port idx\n", __func__); return RTW_PHL_STATUS_FAILURE; } rlink->hw_port = i; return RTW_PHL_STATUS_SUCCESS; } static enum rtw_phl_status _phl_realloc_hw_port(struct phl_info_t *phl, struct rtw_wifi_role_link_t *rlink, u8 new_port) { struct rtw_phl_com_t *phl_com = phl->phl_com; struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); struct hw_band_ctl_t *band_ctrl; band_ctrl = &mr_ctl->band_ctrl[rlink->hw_band]; _os_spinlock(phl_to_drvpriv(phl), &band_ctrl->lock, _bh, NULL); if (!(band_ctrl->port_map & BIT(new_port))) band_ctrl->port_map |= BIT(new_port); _os_spinunlock(phl_to_drvpriv(phl), &band_ctrl->lock, _bh, NULL); rlink->hw_port = new_port; return RTW_PHL_STATUS_SUCCESS; } static enum rtw_phl_status _phl_release_hw_port(struct phl_info_t *phl, struct rtw_wifi_role_link_t *rlink) { struct rtw_phl_com_t *phl_com = phl->phl_com; struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); struct hw_band_ctl_t *band_ctrl; band_ctrl = &mr_ctl->band_ctrl[rlink->hw_band]; _os_spinlock(phl_to_drvpriv(phl), &band_ctrl->lock, _bh, NULL); band_ctrl->port_map &= ~BIT(rlink->hw_port); _os_spinunlock(phl_to_drvpriv(phl), &band_ctrl->lock, _bh, NULL); return RTW_PHL_STATUS_SUCCESS; } static enum rtw_phl_status _phl_alloc_rlink_hw_resource(struct phl_info_t *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, u8 hw_band) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; void *drv = phl_to_drvpriv(phl); struct rtw_phl_com_t *phl_com = phl->phl_com; struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); struct hal_spec_t *hal_spec = phl_get_ic_spec(phl_com); struct hw_band_ctl_t *band_ctrl; u8 port_num, max_port_num; u8 wmm_num, max_wmm_num; int ridx; u8 lidx; band_ctrl = &mr_ctl->band_ctrl[hw_band]; max_port_num = hal_spec->port_num; max_wmm_num = hal_spec->wmm_num; ridx = wrole->id; lidx = rlink->id; _os_spinlock(drv, &band_ctrl->lock, _bh, NULL); /*alloc hw_port or M-BSSID*/ #ifdef RTW_PHL_BCN rlink->hw_mbssid = 0; #endif #ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP if (wrole->type == PHL_RTYPE_VAP) { u8 mbssid_idx; /* 0:root, 1~n:VAP */ /* RTK MBSSID VAP is port 0 function. */ port_num = 0; if ((band_ctrl->port_map & BIT(0)) == 0) { PHL_ERR("Creating VAP w.o. port 0 used.\n"); port_num = max_port_num; goto _exit; } /* Find one unused MBSSID */ for (mbssid_idx = 1; mbssid_idx <= MAX_MBSSID_NUMBER; mbssid_idx++) { if ((band_ctrl->mbssid_map & BIT(mbssid_idx)) == 0) { band_ctrl->mbssid_map |= BIT(mbssid_idx); break; } } if (mbssid_idx > MAX_MBSSID_NUMBER) { PHL_ERR("Can't allocate M-BSSID for VAP. (%u/%02X)\n", MAX_MBSSID_NUMBER, band_ctrl->mbssid_map); goto _exit; } rlink->hw_mbssid = mbssid_idx; band_ctrl->mbssid_cnt++; PHL_PRINT("Creating VAP with M-BSSID %u.\n", rlink->hw_mbssid); } else #endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */ { for (port_num = 0; port_num < max_port_num; port_num++) { if (!(band_ctrl->port_map & BIT(port_num))) { band_ctrl->port_map |= BIT(port_num); break; } } if (port_num == max_port_num) { PHL_ERR("%s Can't allocate hw port\n", __func__); _os_warn_on(1); goto _exit; } } rlink->hw_port = port_num; /*alloc hw_wmm*/ for (wmm_num = 0; wmm_num < max_wmm_num; wmm_num++) { if (!(band_ctrl->wmm_map & BIT(wmm_num))) { band_ctrl->wmm_map |= BIT(wmm_num); break; } } if (wmm_num == max_wmm_num) { PHL_INFO("%s ridx:%d lidx:%d - assigne wmm_id to 0\n", __func__, ridx, lidx); rlink->hw_wmm = 0; } else { rlink->hw_wmm = wmm_num; } #ifdef RTW_WKARD_HW_WMM_ALLOCATE if (rlink->hw_wmm == 0) _os_atomic_inc(phl_to_drvpriv(phl), &rlink->hw_wmm0_ref_cnt); #endif /*set mr_role_map*/ band_ctrl->role_map |= BIT(ridx); rlink->hw_band = hw_band; psts = RTW_PHL_STATUS_SUCCESS; _exit: _os_spinunlock(drv, &band_ctrl->lock, _bh, NULL); if (psts == RTW_PHL_STATUS_SUCCESS) { PHL_INFO("%s ridx:%d lidx:%d success\n", __func__, ridx, lidx); PHL_DUMP_RLINK(phl, wrole, rlink); } return psts; } static enum rtw_phl_status _phl_free_rlink_hw_resource(struct phl_info_t *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; void *drv = phl_to_drvpriv(phl); struct rtw_phl_com_t *phl_com = phl->phl_com; struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); struct hw_band_ctl_t *band_ctrl; int ridx = wrole->id; u8 hw_band = rlink->hw_band; band_ctrl = &mr_ctl->band_ctrl[hw_band]; PHL_DUMP_RLINK(phl, wrole, rlink); _os_spinlock(drv, &band_ctrl->lock, _bh, NULL); /*release hw_port*/ #ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP if (rlink->hw_mbssid != 0) { /* vap */ PHL_INFO("Free MBSSID %u.\n", rlink->hw_mbssid); band_ctrl->mbssid_cnt--; band_ctrl->mbssid_map &= ~BIT(rlink->hw_mbssid); rlink->hw_mbssid = 0; } else #endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */ { band_ctrl->port_map &= ~BIT(rlink->hw_port); } /*release hw_wmm*/ #ifdef RTW_WKARD_HW_WMM_ALLOCATE if (rlink->hw_wmm == 0) { _os_atomic_dec(phl_to_drvpriv(phl), &rlink->hw_wmm0_ref_cnt); if (_os_atomic_read(phl_to_drvpriv(phl), &rlink->hw_wmm0_ref_cnt) == 0) band_ctrl->wmm_map &= ~BIT(rlink->hw_wmm); } else #endif { band_ctrl->wmm_map &= ~BIT(rlink->hw_wmm); } /*release mr_role_map*/ band_ctrl->role_map &= ~BIT(ridx); _os_spinunlock(drv, &band_ctrl->lock, _bh, NULL); psts = RTW_PHL_STATUS_SUCCESS; PHL_INFO("%s ridx-id:%d rlink-id:%d success\n", __func__, ridx, rlink->id); return psts; } #ifdef CONFIG_DBCC_SUPPORT static enum rtw_phl_status _phl_realloc_rlink_hw_resource(struct phl_info_t *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, u8 new_band) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; #ifdef DBG_DBCC_MONITOR_TIME u32 start_t = 0; PHL_FUN_MON_START(&start_t); #endif /* DBG_DBCC_MONITOR_TIME */ if (new_band == rlink->hw_band) { PHL_ERR("%s widx:%d lidx:%d at the same band(%d)\n", __func__, wrole->id, rlink->id, new_band); goto _exit; } psts = _phl_free_rlink_hw_resource(phl, wrole, rlink); if (psts != RTW_PHL_STATUS_SUCCESS) goto _exit; psts = _phl_alloc_rlink_hw_resource(phl, wrole, rlink, new_band); if (psts != RTW_PHL_STATUS_SUCCESS) goto _exit; psts = RTW_PHL_STATUS_SUCCESS; _exit: #ifdef DBG_DBCC_MONITOR_TIME PHL_FUNC_MON_END(phl->phl_com, &start_t, TIME_PHL_MAX); #endif /* DBG_DBCC_MONITOR_TIME */ return psts; } #endif static u8 _phl_search_roleidx_by_addr( struct phl_info_t *phl_info, u8 *mac_addr) { struct rtw_phl_com_t *phl_com = phl_info->phl_com; u8 ridx = MAX_WIFI_ROLE_NUMBER; struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) { if (mr_ctl->role_map & BIT(ridx)) { if (_os_mem_cmp(phl_to_drvpriv(phl_info), phl_com->wifi_roles[ridx].mac_addr, mac_addr, MAC_ALEN) == 0) break; } } #if 0 if (ridx == MAX_WIFI_ROLE_NUMBER) PHL_INFO("%s cannot get rid\n", __func__); #endif return ridx; } struct rtw_wifi_role_link_t * phl_get_rlink_by_hw_band(struct rtw_wifi_role_t *wrole, u8 hw_band) { struct rtw_wifi_role_link_t *rlink = NULL; u8 lidx; bool found = false; for (lidx = 0; lidx < wrole->rlink_num; lidx++) { rlink = get_rlink(wrole, lidx); if (rlink->hw_band == hw_band) { found = true; break; } } if (found == false) rlink = NULL; return rlink; } struct rtw_wifi_role_t * rtw_phl_get_role_by_band_port(void *phl, u8 hw_band, u8 hw_port) { 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]); struct rtw_wifi_role_t *wrole = NULL; struct rtw_wifi_role_link_t *rlink = NULL; u8 ridx = 0; for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) { if (!(band_ctrl->role_map & BIT(ridx))) continue; wrole = phl_get_wrole_by_ridx(phl_info, ridx); if (wrole == NULL) continue; rlink = get_rlink(wrole, RTW_RLINK_PRIMARY); if (rlink->hw_band == hw_band && rlink->hw_port == hw_port) { PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s: phl_get_role_by_band_port(): role_idx(%d) hw_band = %d, hw_port = %d\n", __func__, wrole->id, rlink->hw_band, rlink->hw_port); return wrole; } } return NULL; } struct rtw_wifi_role_t * phl_get_wrole_by_addr(struct phl_info_t *phl_info, u8 *mac_addr) { struct rtw_phl_com_t *phl_com = phl_info->phl_com; int ridx = MAX_WIFI_ROLE_NUMBER; struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); struct rtw_wifi_role_t *wrole = NULL; bool found = false; for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) { if (mr_ctl->role_map & BIT(ridx)) { wrole = &(phl_com->wifi_roles[ridx]); if (wrole->active && _os_mem_cmp(phl_to_drvpriv(phl_info), wrole->mac_addr, mac_addr, MAC_ALEN) == 0) { found = true; break; } } } if (found == false) wrole = NULL; return wrole; } struct rtw_wifi_role_t * phl_get_wrole_by_ridx(struct phl_info_t *phl_info, u8 rold_idx) { struct rtw_phl_com_t *phl_com = phl_info->phl_com; if (rold_idx < MAX_WIFI_ROLE_NUMBER) return &(phl_com->wifi_roles[rold_idx]); return NULL; } static void _phl_role_notify_buf_done(void* priv, struct phl_msg* msg) { struct phl_info_t *phl_info = (struct phl_info_t *)priv; if(msg->inbuf && msg->inlen){ _os_mem_free(phl_to_drvpriv(phl_info), msg->inbuf, msg->inlen); } } #ifdef CONFIG_CMD_DISP static void _phl_role_cmd_done(void* priv, struct phl_msg* msg) { struct phl_info_t *phl_info = (struct phl_info_t *)priv; if(msg->inbuf && msg->inlen){ _os_kmem_free(phl_to_drvpriv(phl_info), msg->inbuf, msg->inlen); } } static void _phl_send_role_notify_cmd(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, enum link_state lstate) { struct phl_msg msg = {0}; struct phl_msg_attribute attr = {0}; struct rtw_role_cmd *rcmd = NULL; rcmd = (struct rtw_role_cmd *)_os_kmem_alloc( phl_to_drvpriv(phl_info), sizeof(struct rtw_role_cmd)); if (rcmd == NULL) { PHL_ERR("%s: alloc role cmd fail.\n", __func__); return; } rcmd->wrole = wrole; rcmd->lstate = lstate; msg.inbuf = (u8 *)rcmd; msg.inlen = sizeof(*rcmd); SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_MRC); SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_ROLE_NTFY); msg.band_idx = HW_BAND_0; attr.completion.completion = _phl_role_cmd_done; attr.completion.priv = phl_info; if (phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL) != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s: dispr_send_msg failed !\n", __func__); goto cmd_fail; } return; cmd_fail: _os_kmem_free(phl_to_drvpriv(phl_info), rcmd, sizeof(struct rtw_role_cmd)); } #endif static enum rtw_phl_status _phl_role_notify(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, enum link_state lstate) { if (lstate >= PHL_LINK_UNKNOWN) { PHL_ERR("%s Unknow lstate:%d\n", __func__, lstate); return RTW_PHL_STATUS_FAILURE; } #if defined(CONFIG_PHL_CMD_BTC) || defined(CONFIG_POWER_SAVE) _phl_send_role_notify_cmd(phl_info, wrole, lstate); #endif return RTW_PHL_STATUS_SUCCESS; } static struct rtw_wifi_role_t * _phl_wifi_role_alloc_sw(struct phl_info_t *phl_info, u8 *mac_addr, enum role_type rtype, u8 ridx, enum rtw_device_type dtype) { struct rtw_phl_com_t *phl_com = phl_info->phl_com; struct rtw_wifi_role_t *role = NULL; struct mr_ctl_t *mr_ctl = phlcom_to_mr_ctrl(phl_com); u8 role_idx = INVALID_WIFI_ROLE_IDX; u8 hw_band; struct rtw_wifi_role_link_t *rlink = NULL; u8 lidx = 0; _os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL); if (ridx == UNSPECIFIED_ROLE_ID) { /*search avaliable rid */ for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) { if (!(mr_ctl->role_map & BIT(role_idx))) { mr_ctl->role_map |= BIT(role_idx); break; } } } else { if (mr_ctl->role_map & BIT(ridx)) { PHL_ERR("role_idx:%d has used\n", ridx); _os_warn_on(1); } else { mr_ctl->role_map |= BIT(ridx); role_idx = ridx; } } _os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL); if (role_idx == INVALID_WIFI_ROLE_IDX) { PHL_ERR("%s Can't get available role idx\n", __func__); _os_warn_on(1); return role; } role = &phl_com->wifi_roles[role_idx]; role->type = rtype; role->mstate = MLME_NO_LINK; if (dtype == DEV_TYPE_MLD) role->rlink_num = phl_com->dev_cap.max_link_num; else role->rlink_num = RTW_ONE_LINK; /*alloc hw_band and hw_port,hw_wmm*/ for (lidx = 0; lidx < role->rlink_num; lidx++) { rlink = get_rlink(role, lidx); if (dtype == DEV_TYPE_MLD) { hw_band = lidx; } else { hw_band = HW_BAND_0; #ifdef CONFIG_DBCC_SUPPORT if ((is_dbcc_sup(phl_com)) && (is_frc_bdand1_role(phl_com, role->id))) { PHL_PRINT("%s Alloc HW_BAND_1 for RoleID(%d) by dbcc_force_rmap(0x%x)\n", __func__, role->id, phl_com->dev_cap.dbcc_force_rmap); hw_band = HW_BAND_1; } #endif /* CONFIG_DBCC_SUPPORT */ } if (RTW_PHL_STATUS_SUCCESS != _phl_alloc_rlink_hw_resource(phl_info, role, rlink, hw_band)) { PHL_ERR("%s alloc_hw resource failed\n", __func__); _os_warn_on(1); role = NULL; /* restore setting of mr_ctl->role_map */ _os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL); mr_ctl->role_map &= ~BIT(role_idx); _os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL); return role; } } _os_mem_cpy(phl_to_drvpriv(phl_info), role->mac_addr, mac_addr, MAC_ALEN); for (lidx = 0; lidx < role->rlink_num; lidx++) { rlink = get_rlink(role, lidx); #ifdef RTW_WKARD_STA_BCN_INTERVAL #ifdef RTW_PHL_BCN if (rtw_phl_role_is_ap_category(role)) { rlink->bcn_cmn.bcn_interval = 100; rlink->mstate = MLME_LINKED; rlink->hiq_win = 50; rlink->bss_params_chg_cnt = 0; } #endif #endif phl_init_rlink_cap(phl_info, rlink); phl_init_protocol_cap(phl_info, role, rlink); } return role; } static enum rtw_phl_status _phl_wifi_role_start(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, struct rtw_phl_mld_t *mld) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE; struct rtw_wifi_role_link_t *rlink; u8 lidx; for (lidx = 0; lidx < mld->sta_num; lidx++) { struct rtw_phl_stainfo_t *sta = mld->phl_sta[lidx]; if (sta->active == false) { psts = phl_alloc_stainfo_hw(phl_info, sta); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s can't alloc self stainfo_hw\n", __func__); _os_warn_on(1); goto _exit; } PHL_INFO("%s sta_info hw - macid:%u %02x:%02x:%02x:%02x:%02x:%02x\n", __func__, sta->macid, sta->mac_addr[0], sta->mac_addr[1], sta->mac_addr[2], sta->mac_addr[3], sta->mac_addr[4], sta->mac_addr[5]); } } for (lidx = 0; lidx < wrole->rlink_num; lidx++) { rlink = get_rlink(wrole, lidx); hsts = rtw_hal_role_cfg(phl_info->hal, wrole, rlink); if(hsts != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("%s hal role cfg failed\n", __func__); _os_warn_on(1); goto _exit; } } wrole->active = true; for (lidx = 0; lidx < wrole->rlink_num; lidx++) { rlink = get_rlink(wrole, lidx); rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, rlink, RX_FLTR_TYPE_MODE_ROLE_INIT); } psts = RTW_PHL_STATUS_SUCCESS; return psts; _exit: return psts; } static enum rtw_phl_status _phl_wifi_role_free_sw(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole) { 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; u8 lidx; /*release hw band,port,wmm*/ for (lidx = 0; lidx < wrole->rlink_num; lidx++) { rlink = get_rlink(wrole, lidx); _phl_free_rlink_hw_resource(phl_info, wrole, rlink); } _os_mem_set(phl_to_drvpriv(phl_info), wrole->mac_addr, 0, MAC_ALEN); _os_spinlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL); mr_ctl->role_map &= ~BIT(wrole->id); _os_spinunlock(phl_to_drvpriv(phl_info), &mr_ctl->lock, _bh, NULL); wrole->rlink_num = 0; wrole->active = false; wrole->mstate = MLME_NO_LINK; wrole->type = PHL_RTYPE_NONE; return RTW_PHL_STATUS_SUCCESS; } #ifdef CONFIG_CMD_DISP struct wr_start_param { struct rtw_wifi_role_t *wrole; struct rtw_phl_mld_t *mld; }; enum rtw_phl_status phl_wifi_role_start_hdl(struct phl_info_t *phl_info, u8 *param) { struct wr_start_param *cmd_wr = (struct wr_start_param *)param; return _phl_wifi_role_start(phl_info, cmd_wr->wrole, cmd_wr->mld); } void phl_wifi_role_start_done(void *drv_priv, u8 *cmd, u32 cmd_len, enum rtw_phl_status status) { if (cmd) { _os_kmem_free(drv_priv, cmd, cmd_len); cmd = NULL; PHL_INFO("%s.....\n", __func__); } } enum rtw_phl_status phl_wifi_role_start(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, struct rtw_phl_mld_t *mld) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; struct wr_start_param *wr_start = NULL; void *drv = phl_to_drvpriv(phl_info); u32 wr_start_len; wr_start_len = sizeof(struct wr_start_param); wr_start = _os_kmem_alloc(drv, wr_start_len); if (wr_start == NULL) { PHL_ERR("%s: alloc wr_start_param failed!\n", __func__); psts = RTW_PHL_STATUS_RESOURCE; goto _exit; } wr_start->wrole = wrole; wr_start->mld = mld; psts = phl_cmd_enqueue(phl_info, /* don't care band, role start will go through all links and start them */ HW_BAND_0, MSG_EVT_ROLE_START, (u8*)wr_start, wr_start_len, phl_wifi_role_start_done, PHL_CMD_WAIT, 0); if (is_cmd_failure(psts)) { /* Send cmd success, but wait cmd fail*/ psts = RTW_PHL_STATUS_FAILURE; PHL_INFO("%s wr-id:%d failure\n", __func__, wrole->id); } else if (psts != RTW_PHL_STATUS_SUCCESS) { /* Send cmd fail */ _os_kmem_free(drv, wr_start, wr_start_len); psts = RTW_PHL_STATUS_FAILURE; PHL_INFO("%s wr-id:%d failure\n", __func__, wrole->id); } else { PHL_INFO("%s wr-id:%d success\n", __func__, wrole->id); } _exit: return psts; } enum rtw_phl_status phl_cmd_get_cur_tsf_hdl(struct phl_info_t *phl_info, struct rtw_phl_port_tsf *tsf) { enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE; hstatus = rtw_hal_get_tsf(phl_info->hal, tsf->hwband, tsf->port, &tsf->tsf_h, &tsf->tsf_l); if (RTW_HAL_STATUS_SUCCESS == hstatus) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } #else enum rtw_phl_status phl_wifi_role_start(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, struct rtw_phl_mld_t *mld) { return _phl_wifi_role_start(phl_info, wrole, mld); } #endif u8 rtw_phl_wifi_role_alloc(void *phl, u8 *mac_addr, u8 **rlink_mac_addr, enum role_type rtype, u8 ridx, struct rtw_wifi_role_t **wifi_role, enum rtw_device_type dtype, bool ignore_hw_fail) { struct phl_info_t *phl_info = (struct phl_info_t *)phl; struct rtw_phl_com_t *phl_com = phl_info->phl_com; u8 role_idx = INVALID_WIFI_ROLE_IDX; struct rtw_wifi_role_t *role = NULL; struct rtw_phl_stainfo_t *phl_sta = NULL; enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; struct macid_ctl_t *mc = phl_to_mac_ctrl(phl_info); u16 macid = mc->max_num; struct rtw_phl_mld_t *mld = NULL; struct rtw_wifi_role_link_t *rlink; u8 lidx = 0; #ifdef DBG_MONITOR_TIME u32 start_t = 0; PHL_FUN_MON_START(&start_t); #endif /* DBG_MONITOR_TIME */ if (mac_addr == NULL) { PHL_ERR("%s mac_addr == NULL\n", __func__); goto _exit; } /*search rid by mac_addr, if had assigned then return role index*/ role_idx = _phl_search_roleidx_by_addr(phl_info, mac_addr); if (role_idx != INVALID_WIFI_ROLE_IDX) { PHL_INFO("%s wifi-role(%d) had allociated\n", __func__, role_idx); *wifi_role = &phl_com->wifi_roles[role_idx]; return role_idx; } role = _phl_wifi_role_alloc_sw(phl_info, mac_addr, rtype, ridx, dtype); if (role == NULL) { PHL_ERR("%s role alloc sw failed\n", __func__); _os_warn_on(1); goto _exit; } /* alloc mld for self */ mld = phl_alloc_mld(phl_info, role, mac_addr, dtype); if (mld == NULL) { PHL_ERR("%s can't alloc self mld\n", __func__); _os_warn_on(1); goto _err_mld; } /*alloc sta_info for self*/ for (lidx = 0; lidx < role->rlink_num; lidx++) { rlink = get_rlink(role, lidx); if (rlink_mac_addr[lidx] == NULL) { PHL_ERR("%s rlink_mac_addr == NULL\n", __func__); if (lidx != 0) phl_wifi_role_free_stainfo_sw(phl_info, role); goto _err_stainfo_sw; } _os_mem_cpy(phl_to_drvpriv(phl_info), rlink->mac_addr, rlink_mac_addr[lidx], MAC_ALEN); phl_sta = phl_alloc_stainfo_sw(phl_info, rlink->mac_addr, role, dtype, macid, rlink); if (phl_sta == NULL) { PHL_ERR("%s can't alloc self stainfo_sw\n", __func__); _os_warn_on(1); if (lidx != 0) phl_wifi_role_free_stainfo_sw(phl_info, role); goto _err_stainfo_sw; } rtw_phl_link_mld_stainfo(mld, phl_sta); macid = phl_sta->macid; } psts = phl_wifi_role_start(phl_info, role, mld); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s role start failed\n", __func__); if (!ignore_hw_fail) { _os_warn_on(1); goto _err_role_start; } SET_STATUS_FLAG(role->status, WR_STATUS_HW_ALLOC_FAIL); } *wifi_role = role; role_idx = role->id; PHL_DUMP_MR_EX(phl_info); #ifdef DBG_MONITOR_TIME PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_ROLE_ALLOC); #endif /* DBG_MONITOR_TIME */ return role_idx; _err_role_start: phl_wifi_role_free_stainfo_sw(phl_info, role); _err_stainfo_sw: phl_wifi_role_free_mld(phl_info, role); _err_mld: _phl_wifi_role_free_sw(phl_info, role); _exit: return INVALID_WIFI_ROLE_IDX; } #ifdef CONFIG_DBCC_SUPPORT /*execut this api after DBCC config success*/ enum rtw_phl_status _phl_ap_role_assoc_sta_upt(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE; struct phl_queue *sta_queue = NULL; struct rtw_phl_stainfo_t *sta; bool is_ap_assoc = false; struct rtw_wifi_role_link_t *rlink = NULL; u8 ridx; for (ridx = 0; ridx < wrole->rlink_num; ridx++) { rlink = get_rlink(wrole, ridx); sta_queue = &rlink->assoc_sta_queue; _os_spinlock(phl_to_drvpriv(phl_info), &sta_queue->lock, _bh, NULL); if (sta_queue->cnt >= 2) is_ap_assoc = true; _os_spinunlock(phl_to_drvpriv(phl_info), &sta_queue->lock, _bh, NULL); if (is_ap_assoc == false) { PHL_INFO("wr(%d,%d) have no assoc sta\n", wrole->id, rlink->id); continue; } phl_list_for_loop(sta, struct rtw_phl_stainfo_t, &sta_queue->queue, list) { if (sta && _os_mem_cmp(phl_to_drvpriv(phl_info), sta->mac_addr, wrole->mac_addr, MAC_ALEN) != 0) { /*phl_re_register_tx_ring - phl_sta*/ psts = phl_update_stainfo_sw(phl_info, sta); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s macid:%d phl_update_stainfo_sw failed\n", __func__, sta->macid); _os_warn_on(1); goto _err; } /*[HALMAC][HALBB]*/ hsts = rtw_hal_change_sta_entry(phl_info->hal, sta, PHL_UPD_ROLE_BAND_SW); if (hsts != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("%s macid:%d rtw_hal_update_sta_entry failure!\n", __func__, sta->macid); _os_warn_on(1); psts = RTW_PHL_STATUS_FAILURE; goto _err; } } } } psts = RTW_PHL_STATUS_SUCCESS; _err: return psts; } enum rtw_phl_status phl_wifi_role_realloc_band(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, enum phl_band_idx new_band) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE; struct rtw_phl_stainfo_t *phl_sta = NULL; u32 func_en = false; #ifdef DBG_DBCC_MONITOR_TIME u32 start_t = 0; PHL_FUN_MON_START(&start_t); #endif /* DBG_DBCC_MONITOR_TIME */ if (new_band == rlink->hw_band) goto _exit; PHL_DUMP_ROLE_EX(phl_info, wrole); PHL_DUMP_RLINK(phl_info, wrole, rlink); /*[HALMAC] - disable hw port*/ hsts = rtw_hal_role_cfg_ex(phl_info->hal, rlink, PCFG_FUNC_SW, &func_en); if(hsts != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("%s hal role disable failed\n", __func__); _os_warn_on(1); goto _exit; } phl_sta = rtw_phl_get_stainfo_self(phl_info, rlink); /*re-alloc sw resource - band, port, wmm*/ psts = _phl_realloc_rlink_hw_resource(phl_info, wrole, rlink, new_band); if (psts != RTW_PHL_STATUS_SUCCESS) goto _exit; /*phl_re_register_tx_ring - phl_sta*/ psts = phl_update_stainfo_sw(phl_info, phl_sta); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s phl_update_stainfo_sw failed\n", __func__); _os_warn_on(1); goto _exit; } /*[HALMAC][HALBB]*/ hsts = rtw_hal_change_sta_entry(phl_info->hal, phl_sta, PHL_UPD_ROLE_BAND_SW); if (hsts != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("rtw_hal_update_sta_entry failure!\n"); psts = RTW_PHL_STATUS_FAILURE; goto _exit; } phl_init_rlink_cap(phl_info, rlink); phl_init_protocol_cap(phl_info, wrole, rlink); /*[HALMAC]*/ hsts = rtw_hal_role_cfg(phl_info->hal, wrole, rlink); if(hsts != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("%s hal role cfg failed\n", __func__); _os_warn_on(1); psts = RTW_PHL_STATUS_FAILURE; goto _exit; } if (rtw_phl_role_is_ap_category(wrole)) { psts = _phl_ap_role_assoc_sta_upt(phl_info, wrole); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s _phl_ap_role_assoc_sta_upt failed\n", __func__); _os_warn_on(1); goto _exit; } } psts = RTW_PHL_STATUS_SUCCESS; PHL_DUMP_ROLE_EX(phl_info, wrole); PHL_DUMP_RLINK(phl_info, wrole, rlink); _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 psts; } enum rtw_phl_status rtw_phl_wifi_role_realloc_band(void *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink) { enum phl_band_idx new_band; if (rlink->hw_band == HW_BAND_0) new_band = HW_BAND_1; else new_band = HW_BAND_0; phl_wifi_role_realloc_band((struct phl_info_t *)phl, wrole, rlink, new_band); return RTW_PHL_STATUS_SUCCESS; } #endif /*CONFIG_DBCC_SUPPORT*/ enum rtw_phl_status phl_wifi_role_realloc_port(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, u8 new_port) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; enum rtw_hal_status hsts = RTW_HAL_STATUS_FAILURE; u32 func_en = false; struct rtw_phl_stainfo_t *phl_sta = NULL; if (new_port == rlink->hw_port) goto _exit; PHL_DUMP_ROLE_EX(phl_info, wrole); PHL_DUMP_RLINK(phl_info, wrole, rlink); /*free org-resource*/ phl_sta = rtw_phl_get_stainfo_self(phl_info, rlink); psts = phl_free_stainfo_hw(phl_info, phl_sta); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s free self-sta failed\n", __func__); _os_warn_on(1); goto _exit; } /*disable hw port*/ hsts = rtw_hal_role_cfg_ex(phl_info->hal, rlink, PCFG_FUNC_SW, &func_en); if(hsts != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("%s hal role disable failed\n", __func__); _os_warn_on(1); psts = RTW_PHL_STATUS_FAILURE; goto _exit; } /*release hw port*/ psts = _phl_release_hw_port(phl_info, rlink); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s release port failed\n", __func__); _os_warn_on(1); goto _exit; } /*re-alloc hw resource*/ psts = _phl_realloc_hw_port(phl_info, rlink, new_port); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s realloc port failed\n", __func__); _os_warn_on(1); goto _exit; } psts = phl_alloc_stainfo_hw(phl_info, phl_sta); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s alloc sta hw failed\n", __func__); _os_warn_on(1); goto _exit; } /*Register RA*/ if (rtw_phl_role_is_client_category(wrole) && wrole->mstate == MLME_LINKED) { psts = phl_change_stainfo(phl_info, phl_sta, PHL_UPD_STA_INFO_CHANGE); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR(" phl_change_stainfo!\n"); goto _exit; } } hsts = rtw_hal_role_cfg(phl_info->hal, wrole, rlink); if(hsts != RTW_HAL_STATUS_SUCCESS) { PHL_ERR("%s hal role cfg failed\n", __func__); _os_warn_on(1); psts = RTW_PHL_STATUS_FAILURE; goto _exit; } psts = RTW_PHL_STATUS_SUCCESS; PHL_DUMP_ROLE_EX(phl_info, wrole); PHL_DUMP_RLINK(phl_info, wrole, rlink); _exit: return psts; } enum rtw_phl_status rtw_phl_wifi_role_realloc_port(void *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, u8 new_port) { return phl_wifi_role_realloc_port((struct phl_info_t *)phl, wrole, rlink, new_port); } enum rtw_phl_status phl_wifi_role_realloc_wmm(struct phl_info_t *phl_info, struct rtw_wifi_role_link_t *rlink, u8 new_wmm) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; if (new_wmm == rlink->hw_wmm) goto _exit; psts = RTW_PHL_STATUS_SUCCESS; _exit: return psts; } enum rtw_phl_status phl_role_noa_notify(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole) { _phl_role_notify(phl_info, wrole, PHL_LINK_UP_NOA); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status phl_role_ap_client_notify(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, u8 link_sts, u16 client_macid) { enum link_state lstate = PHL_LINK_UNKNOWN; #ifdef CONFIG_BTCOEX struct rtw_wifi_role_link_t *rlink = get_rlink(wrole, RTW_RLINK_PRIMARY); #endif /* CONFIG_BTCOEX */ if (link_sts == MLME_LINKING) { lstate = PHL_ClIENT_JOINING; } else if (link_sts == MLME_NO_LINK) { lstate = PHL_ClIENT_LEFT; } else { PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s macid(%d), link_sts don't support(%d)\n", __func__, client_macid, link_sts); return RTW_PHL_STATUS_FAILURE; } #ifdef CONFIG_BTCOEX rtw_hal_btc_ap_client_notify(phl_info->hal, rlink, lstate); #endif /* CONFIG_BTCOEX */ #ifdef CONFIG_MCC_SUPPORT phl_mcc_ap_client_notify(phl_info, wrole, lstate); #endif /* CONFIG_MCC_SUPPORT */ #ifdef CONFIG_P2PPS phl_p2pps_ap_client_notify(phl_info, wrole, lstate, client_macid); #endif return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status phl_role_notify(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole) { enum link_state lstate = PHL_LINK_UNKNOWN; switch (wrole->type) { case PHL_RTYPE_STATION: case PHL_RTYPE_P2P_GC: { lstate = (wrole->mstate == MLME_NO_LINK) ? PHL_LINK_STOPPED : PHL_LINK_STARTED; } break; case PHL_RTYPE_AP: case PHL_RTYPE_VAP: case PHL_RTYPE_MESH: case PHL_RTYPE_P2P_GO: { lstate = (wrole->mstate == MLME_NO_LINK) ? PHL_LINK_STOPPED : PHL_LINK_STARTED; } break; case PHL_RTYPE_NONE: case PHL_RTYPE_ADHOC: case PHL_RTYPE_ADHOC_MASTER: case PHL_RTYPE_MONITOR: case PHL_RTYPE_P2P_DEVICE: case PHL_RTYPE_NAN: case PHL_MLME_MAX: PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Unsupported case:%d in wrole notify, please check it\n", __func__, wrole->type); break; default: PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s role-type(%d) not support\n", __func__, wrole->type); break; } _phl_role_notify(phl_info, wrole, lstate); return RTW_PHL_STATUS_SUCCESS; } static enum rtw_phl_status _phl_rlink_set_bcn_early_rpt(struct phl_info_t *phl, struct rtw_wifi_role_link_t *rlink, u8 en) { enum rtw_hal_status status; status = rtw_hal_set_bcn_early_rpt(phl->hal, rlink->hw_band, rlink->hw_port, en); if (status != RTW_HAL_STATUS_SUCCESS) return RTW_PHL_STATUS_FAILURE; return RTW_PHL_STATUS_SUCCESS; } /** * This function is called once wifi info changed * (see enum wr_chg_id) * @phl: see phl_info_t * @wrole: information is updated for this wifi role * @rlink: update information for specific role link * @chg_id: see enum wr_chg_id * @chg_info: the change info to be update */ enum rtw_phl_status phl_wifi_role_change(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, enum wr_chg_id chg_id, const void *chg_info ) { enum rtw_phl_status pstate = RTW_PHL_STATUS_FAILURE; enum rtw_hal_status hstate; struct rtw_phl_stainfo_t *sta = NULL; enum phl_upd_mode mode = PHL_UPD_ROLE_MAX; void *drv = phl_to_drvpriv(phl_info); struct rtw_wifi_role_link_t *tmp_rlink = NULL; u8 idx = 0; switch (chg_id) { case WR_CHG_TYPE: { enum role_type type = *(enum role_type *)chg_info; u8 mac_addr[MAC_ALEN] = {0}; if (wrole->type == type) { PHL_WARN("wrole type(%d) not change\n", wrole->type); pstate = RTW_PHL_STATUS_SUCCESS; return pstate; } #ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP /* VAP does not own a port. Role type should not be changed * in active state, or the root AP could be affected. */ if (wrole->type == PHL_RTYPE_VAP) { PHL_ERR("Role type VAP can not be changed.\n"); return RTW_PHL_STATUS_INVALID_PARAM; } #endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */ PHL_INFO("wrole type(%d) change to type(%d)\n", wrole->type, type); _os_mem_cpy(drv, mac_addr, wrole->mac_addr, MAC_ALEN); for (idx = 0; idx < wrole->rlink_num; idx++) { tmp_rlink = get_rlink(wrole, idx); sta = rtw_phl_get_stainfo_self(phl_info, tmp_rlink); if (sta) { if (type == PHL_RTYPE_TDLS || wrole->type == PHL_RTYPE_TDLS) { wrole->type = type; pstate = RTW_PHL_STATUS_SUCCESS; } else { wrole->type = type; wrole->mstate = MLME_NO_LINK; tmp_rlink->mstate = MLME_NO_LINK; #ifdef RTW_WKARD_STA_BCN_INTERVAL #ifdef RTW_PHL_BCN if (rtw_phl_role_is_ap_category(wrole)) { wrole->mstate = MLME_LINKED; tmp_rlink->bcn_cmn.bcn_interval = 100; tmp_rlink->mstate = MLME_LINKED; tmp_rlink->hiq_win = 16; /* unit: ms */ } #endif #endif phl_init_rlink_cap(phl_info, tmp_rlink); phl_init_protocol_cap(phl_info, wrole, tmp_rlink); rtw_hal_role_cfg(phl_info->hal, wrole, tmp_rlink); rtw_phl_mr_set_rxfltr_type_by_mode(phl_info, tmp_rlink, RX_FLTR_TYPE_MODE_ROLE_INIT); if (wrole->rlink_num > 1) mac_addr[5]++; _os_mem_cpy(drv, sta->mac_addr, mac_addr, MAC_ALEN); mode = PHL_UPD_ROLE_TYPE_CHANGE; pstate = phl_change_stainfo(phl_info, sta, mode); /*rtw_hal_change_sta_entry(phl_info->hal, sta);*/ } } else { PHL_ERR("cannot get stainfo_self\n"); } } PHL_DUMP_MR_EX(phl_info); } break; case WR_CHG_MADDR: { u8 *maddr = (u8 *)chg_info; if (wrole->mstate == MLME_LINKED) { PHL_WARN("Do not change wrole maddr when linked\n"); return RTW_PHL_STATUS_SUCCESS; } if (rlink == NULL) { if(_os_mem_cmp(drv, wrole->mac_addr, maddr, MAC_ALEN) == 0) { PHL_WARN("wrole maddr %02x:%02x:%02x:%02x:%02x:%02x not change\n", maddr[0], maddr[1], maddr[2], maddr[3], maddr[4], maddr[5]); return RTW_PHL_STATUS_SUCCESS; } PHL_INFO("wrole maddr %02x:%02x:%02x:%02x:%02x:%02x change to %02x:%02x:%02x:%02x:%02x:%02x\n", wrole->mac_addr[0], wrole->mac_addr[1], wrole->mac_addr[2], wrole->mac_addr[3], wrole->mac_addr[4], wrole->mac_addr[5], maddr[0], maddr[1], maddr[2], maddr[3], maddr[4], maddr[5]); _os_mem_cpy(drv, wrole->mac_addr, maddr, MAC_ALEN); } else { if(_os_mem_cmp(drv, rlink->mac_addr, maddr, MAC_ALEN) == 0) { PHL_WARN("rlink maddr %02x:%02x:%02x:%02x:%02x:%02x not change\n", maddr[0], maddr[1], maddr[2], maddr[3], maddr[4], maddr[5]); return RTW_PHL_STATUS_SUCCESS; } PHL_INFO("rlink maddr %02x:%02x:%02x:%02x:%02x:%02x change to %02x:%02x:%02x:%02x:%02x:%02x\n", rlink->mac_addr[0], rlink->mac_addr[1], rlink->mac_addr[2], rlink->mac_addr[3], rlink->mac_addr[4], rlink->mac_addr[5], maddr[0], maddr[1], maddr[2], maddr[3], maddr[4], maddr[5]); _os_mem_cpy(drv, rlink->mac_addr, maddr, MAC_ALEN); sta = rtw_phl_get_stainfo_self(phl_info, rlink); if (sta) { mode = PHL_UPD_ROLE_INFO_CHANGE; _os_mem_cpy(drv, sta->mac_addr, wrole->mac_addr, MAC_ALEN); pstate = phl_change_stainfo(phl_info, sta, mode); /*rtw_hal_change_sta_entry(phl_info->hal, sta);*/ } } } break; case WR_CHG_AP_PARAM: { struct rtw_ap_param *param = (struct rtw_ap_param *)chg_info; if (!rtw_phl_role_is_ap_category(wrole)) break; if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } if (param->cfg_id == CFG_BSS_CLR) { u32 bsscolor = param->value; rlink->protocol_cap.bsscolor = (u8)bsscolor; rtw_hal_role_cfg_ex(phl_info->hal, rlink, PCFG_BSS_CLR, &bsscolor); } else if (param->cfg_id == CFG_BCN_DRP_ALL) { u32 bcn_drp_en = param->value; rtw_hal_role_cfg_ex(phl_info->hal, rlink, PCFG_BCN_DRP_ALL, &bcn_drp_en); } /* else if (param->cfg_id == CFG_HIQ_DTIM) */ else { PHL_INFO("wrole->type(%d) WR_CHG_AP_PARAM todo.....\n", wrole->type); } pstate = RTW_PHL_STATUS_SUCCESS; } break; case WR_CHG_EDCA_PARAM: { struct rtw_edca_param *param = (struct rtw_edca_param*)chg_info; if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } hstate = rtw_hal_set_edca(phl_info->hal, rlink, param->ac, param->param); if (hstate == RTW_HAL_STATUS_SUCCESS) { pstate = RTW_PHL_STATUS_SUCCESS; } else { pstate = RTW_PHL_STATUS_FAILURE; break; } } break; case WR_CHG_MU_EDCA_PARAM: { struct rtw_mu_edca_param *param = (struct rtw_mu_edca_param*)chg_info; if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } hstate = rtw_hal_set_mu_edca(phl_info->hal, rlink->hw_band, param->ac, param->timer, (param->cw & 0x0f), (param->cw>>4), param->aifsn); if (hstate == RTW_HAL_STATUS_SUCCESS) { pstate = RTW_PHL_STATUS_SUCCESS; } else { pstate = RTW_PHL_STATUS_FAILURE; break; } } break; case WR_CHG_MULTI_MU_EDCA_PARAM: { struct rtw_multi_mu_edca_param *param = (struct rtw_multi_mu_edca_param*)chg_info; if (param->num > ACQ_MAX) { PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "WR_CHG_MULTI_MU_EDCA_PARAM: Invalid param_q->num(%d)\n", param->num); break; } if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } for (idx = 0; idx < param->num; idx++) { hstate = rtw_hal_set_mu_edca(phl_info->hal, rlink->hw_band, param->mu_edca[idx].ac, param->mu_edca[idx].timer, (param->mu_edca[idx].cw & 0x0f), (param->mu_edca[idx].cw >> 4), param->mu_edca[idx].aifsn); if (hstate != RTW_HAL_STATUS_SUCCESS) { PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "WR_CHG_MULTI_MU_EDCA_PARAM: cfg edca[%d] fail\n", idx); break; } } pstate = RTW_PHL_STATUS_SUCCESS; } break; case WR_CHG_MU_EDCA_CFG: { u8 val = *(u8 *)chg_info; if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } hstate = rtw_hal_set_mu_edca_ctrl(phl_info->hal, rlink->hw_band, rlink->hw_wmm, val); if (hstate == RTW_HAL_STATUS_SUCCESS) { pstate = RTW_PHL_STATUS_SUCCESS; } else { pstate = RTW_PHL_STATUS_FAILURE; break; } } break; case WR_CHG_BSS_COLOR: { u32 val = *(u8 *)chg_info; if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } hstate = rtw_hal_role_cfg_ex(phl_info->hal, rlink, PCFG_BSS_CLR, &val); if (hstate == RTW_HAL_STATUS_SUCCESS) { pstate = RTW_PHL_STATUS_SUCCESS; } else { pstate = RTW_PHL_STATUS_FAILURE; break; } } break; case WR_CHG_RTS_TH: { struct rtw_rts_threshold *val = (struct rtw_rts_threshold *)chg_info; if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } hstate = rtw_hal_config_rts_th(phl_info->hal, rlink->hw_band, val->rts_time_th, val->rts_len_th); if (hstate == RTW_HAL_STATUS_SUCCESS) { pstate = RTW_PHL_STATUS_SUCCESS; } else { pstate = RTW_PHL_STATUS_FAILURE; break; } } break; case WR_CHG_DFS_HE_TB_CFG: { u8 val = *(u8 *)chg_info; hstate = rtw_hal_set_dfs_tb_ctrl(phl_info->hal, val); if (hstate == RTW_HAL_STATUS_SUCCESS) pstate = RTW_PHL_STATUS_SUCCESS; } break; case WR_CHG_TRX_PATH: { struct rtw_trx_path_param *param = (struct rtw_trx_path_param*)chg_info; hstate = rtw_hal_cfg_trx_path(phl_info->hal, param->tx, param->tx_nss, param->rx, param->rx_nss); if (hstate == RTW_HAL_STATUS_SUCCESS) pstate = RTW_PHL_STATUS_SUCCESS; } break; case WR_CHG_STBC_CFG: { if (rlink == NULL) { PHL_WARN("%s: Target rlink is NULL!\n", __func__); break; } phl_init_proto_stbc_cap(rlink, phl_info, &rlink->protocol_cap); } break; case WR_CHG_LSN_DISCOV: if (wrole->type == PHL_RTYPE_P2P_DEVICE) { bool en = *(u8 *)chg_info; if (rlink == NULL) { PHL_WARN("%s(WR_CHG_LSN_DISCOV): Target rlink is NULL!\n", __func__); break; } PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s: WR_CHG_LSN_DISCOV(%d)\n", __func__, en); if (en) SET_STATUS_FLAG(wrole->status, WR_STATUS_LSN_DISCOV); else CLEAR_STATUS_FLAG(wrole->status, WR_STATUS_LSN_DISCOV); phl_mr_info_upt(phl_info, rlink); rtw_phl_mr_rx_filter_opt(phl_info, rlink); } break; case WR_CHG_FIX_ANT_DIV: { u8 antIndex = *(u8 *)chg_info; rtw_hal_antdiv_fix_ant(phl_info->hal, antIndex); } break; case WR_CHG_BCN_EARLY_RPT_CFG: { u8 en = *(u8 *)chg_info; if (rlink == NULL) { /* Set bcn early rpt for all rlinks */ for (idx = 0; idx < wrole->rlink_num; idx++) { tmp_rlink = get_rlink(wrole, idx); pstate = _phl_rlink_set_bcn_early_rpt(phl_info, tmp_rlink, en); if (pstate == RTW_PHL_STATUS_FAILURE) break; } } else { pstate = _phl_rlink_set_bcn_early_rpt(phl_info, rlink, en); } } break; case WR_CHG_MAX: PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Unsupported case:%d, please check it\n", __func__, chg_id); break; default : PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: unknown chg_id(%d), please check it\n", __func__, chg_id); break; }; return pstate; } #ifdef CONFIG_CMD_DISP enum rtw_phl_status phl_wifi_role_chg_hdl(struct phl_info_t *phl_info, u8 *param) { struct wr_chg_param *wr_chg = (struct wr_chg_param *)param; return phl_wifi_role_change(phl_info, wr_chg->wrole, wr_chg->rlink, wr_chg->id, wr_chg->info); } void phl_wifi_role_chg_done(void *drv_priv, u8 *cmd, u32 cmd_len, enum rtw_phl_status status) { struct wr_chg_param *wr_chg = NULL; if (cmd == NULL || cmd_len == 0) { PHL_ERR("%s buf == NULL || buf_len == 0\n", __func__); _os_warn_on(1); return; } wr_chg = (struct wr_chg_param *)cmd; PHL_INFO("%s - id:%d .....\n", __func__, wr_chg->id); if (wr_chg->info) _os_kmem_free(drv_priv, wr_chg->info, wr_chg->info_len); _os_kmem_free(drv_priv, cmd, cmd_len); cmd = NULL; } enum rtw_phl_status rtw_phl_cmd_wrole_change(void *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, enum wr_chg_id chg_id, const u8 *chg_info, u8 chg_info_len, enum phl_cmd_type cmd_type, u32 cmd_timeout ) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; struct phl_info_t *phl_info = (struct phl_info_t *)phl; void *drv = phl_to_drvpriv(phl_info); struct wr_chg_param *wr_chg = NULL; u32 wr_chg_len = 0; if (cmd_type == PHL_CMD_DIRECTLY) { psts = phl_wifi_role_change(phl_info, wrole, rlink, chg_id, chg_info); goto _exit; } wr_chg_len = sizeof(struct wr_chg_param); wr_chg = _os_kmem_alloc(drv, wr_chg_len); if (wr_chg == NULL) { PHL_ERR("%s: alloc wr_chg_param failed!\n", __func__); psts = RTW_PHL_STATUS_RESOURCE; goto _exit; } _os_mem_set(drv, wr_chg, 0, wr_chg_len); wr_chg->wrole = wrole; wr_chg->rlink = rlink; wr_chg->id = chg_id; wr_chg->info_len = chg_info_len; wr_chg->info = _os_kmem_alloc(drv, chg_info_len); if (wr_chg->info == NULL) { PHL_ERR("%s: alloc wr_chg_info failed!\n", __func__); psts = RTW_PHL_STATUS_RESOURCE; goto _err_info; } _os_mem_set(drv, wr_chg->info, 0, chg_info_len); _os_mem_cpy(drv, wr_chg->info, chg_info, chg_info_len); psts = phl_cmd_enqueue(phl_info, /* don't care band, role change will go through all links and change settings */ HW_BAND_0, MSG_EVT_ROLE_CHANGE, (u8*)wr_chg, wr_chg_len, phl_wifi_role_chg_done, cmd_type, cmd_timeout); if (is_cmd_failure(psts)) { /* Send cmd success, but wait cmd fail*/ psts = RTW_PHL_STATUS_FAILURE; PHL_INFO("%s wr-id:%d failure\n", __func__, wrole->id); } else if (psts != RTW_PHL_STATUS_SUCCESS) { /* Send cmd fail */ psts = RTW_PHL_STATUS_FAILURE; PHL_INFO("%s wr-id:%d failure\n", __func__, wrole->id); goto _err_cmd; } else { PHL_INFO("%s wr-id:%d success\n", __func__, wrole->id); } return psts; _err_cmd: if (wr_chg->info) _os_kmem_free(drv, wr_chg->info, wr_chg->info_len); _err_info: if (wr_chg) _os_kmem_free(drv, wr_chg, wr_chg_len); _exit: return psts; } #else enum rtw_phl_status rtw_phl_cmd_wrole_change(void *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink, enum wr_chg_id chg_id, const u8 *chg_info, u8 chg_info_len, enum phl_cmd_type cmd_type, u32 cmd_timeout ) { return phl_wifi_role_change((struct phl_info_t *)phl, wrole, rlink, chg_id, chg_info); } #endif /*CONFIG_CMD_DISP*/ enum rtw_phl_status _phl_wifi_role_stop(struct phl_info_t *phl_i, struct rtw_wifi_role_t *wrole) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; u8 lidx; struct rtw_wifi_role_link_t *rlink; #ifdef CONFIG_RTW_SUPPORT_MBSSID_VAP if (wrole->type == PHL_RTYPE_VAP) { u32 param = 0; for (lidx = 0; lidx < wrole->rlink_num; lidx++) { rlink = get_rlink(wrole, lidx); PHL_PRINT("Stop MBSSID %u.\n", rlink->hw_mbssid); /* Configure port for M-BSSID */ rtw_hal_role_cfg_ex(phl_i->hal, rlink, PCFG_MBSSID_EN, ¶m); } } #endif /* CONFIG_RTW_SUPPORT_MBSSID_VAP */ wrole->active = false; psts = phl_wifi_role_free_stainfo_hw(phl_i, wrole); if (psts != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s wr free stainfo_hw failed\n", __func__); _os_warn_on(1); goto _exit; } /*hw port cfg - mac_port_deinit*/ for (lidx = 0; lidx < wrole->rlink_num; lidx++) { rlink = get_rlink(wrole, lidx); if (RTW_HAL_STATUS_SUCCESS != rtw_hal_role_deinit(phl_i->hal, rlink)) { PHL_ERR("%s wr deinit failed for link idx(%d), it may influence power consumption\n", __func__, lidx); psts = RTW_PHL_STATUS_FAILURE; } } _exit: return psts; } #ifdef CONFIG_CMD_DISP enum rtw_phl_status phl_wifi_role_stop_hdl(struct phl_info_t *phl_info, u8 *param) { struct rtw_wifi_role_t *wrole = (struct rtw_wifi_role_t *)param; return _phl_wifi_role_stop(phl_info, wrole); } void phl_wifi_role_stop_done(void *drv_priv, u8 *cmd, u32 cmd_len, enum rtw_phl_status status) { if (cmd) { struct rtw_wifi_role_t *wrole = NULL; wrole = (struct rtw_wifi_role_t *)cmd; if (is_cmd_failure(status) && (RTW_PHL_STATUS_SUCCESS != status)) PHL_ERR("%s wrole(%d) fail status(%d).....\n", __func__, wrole->id, status); else PHL_INFO("%s wrole(%d) success.....\n", __func__, wrole->id); } } enum rtw_phl_status phl_wifi_role_stop(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole) { enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; psts = phl_cmd_enqueue(phl_info, HW_BAND_0, MSG_EVT_ROLE_STOP, (u8 *)wrole, 0, phl_wifi_role_stop_done, PHL_CMD_WAIT, 0); if (is_cmd_failure(psts)) { /* Send cmd success, but wait cmd fail*/ psts = RTW_PHL_STATUS_FAILURE; PHL_INFO("%s wr-id:%d failure\n", __func__, wrole->id); } else if (psts != RTW_PHL_STATUS_SUCCESS) { /* Send cmd fail */ psts = RTW_PHL_STATUS_FAILURE; PHL_INFO("%s wr-id:%d failure\n", __func__, wrole->id); } else { PHL_INFO("%s wr-id:%d success\n", __func__, wrole->id); } return psts; } #else enum rtw_phl_status phl_wifi_role_stop(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole) { return _phl_wifi_role_stop(phl_info, wrole); } #endif void rtw_phl_wifi_role_free(void *phl, u8 role_idx) { struct phl_info_t *phl_info = (struct phl_info_t *)phl; struct rtw_phl_com_t *phl_com = phl_info->phl_com; struct rtw_wifi_role_t *wrole = NULL; #ifdef DBG_MONITOR_TIME u32 start_t = 0; PHL_FUN_MON_START(&start_t); #endif /* DBG_MONITOR_TIME */ if (role_idx >= MAX_WIFI_ROLE_NUMBER) { PHL_ERR("%s invalid role index :%d\n", __func__, role_idx); goto _exit; } wrole = &phl_com->wifi_roles[role_idx]; if (phl_wifi_role_stop(phl_info, wrole) != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s role_stop failed :%d\n", __func__, role_idx); _os_warn_on(1); } if (phl_wifi_role_free_stainfo_sw(phl_info, wrole) != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s wr free stainfo_sw failed\n", __func__); _os_warn_on(1); } if (phl_wifi_role_free_mld(phl_info, wrole) != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s wr free mld failed\n", __func__); _os_warn_on(1); } _phl_wifi_role_free_sw(phl_info, wrole); _exit: #ifdef DBG_MONITOR_TIME PHL_FUNC_MON_END(phl_com, &start_t, TIME_PHL_ROLE_FREE); #endif /* DBG_MONITOR_TIME */ PHL_DUMP_MR_EX(phl_info); } #ifdef CONFIG_CMD_DISP enum rtw_phl_status phl_register_mrc_module(struct phl_info_t *phl_info) { enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE; 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; struct phl_cmd_dispatch_engine *disp_eng = &(phl_info->disp_eng); u8 i = 0; for(i = 0; i < disp_eng->phy_num; i++) { phl_status = phl_disp_eng_register_module(phl_info, i, PHL_MDL_MRC, &bk_ops); if (RTW_PHL_STATUS_SUCCESS != phl_status) { PHL_ERR("%s register MRC module in cmd disp failed :%d\n", __func__, i+1); goto error_register_bk; } } return phl_status; error_register_bk: while(i > 0){ phl_status = phl_disp_eng_deregister_module(phl_info, --i, PHL_MDL_MRC); if (RTW_PHL_STATUS_SUCCESS != phl_status) { PHL_ERR("%s deregister MRC module in cmd disp failed :%d\n", __func__, i+1); } } return RTW_PHL_STATUS_FAILURE; } #endif /* * return role map of excluded role from suspension */ static u8 _phl_get_excld_susp_role_map(struct phl_info_t *phl_i, enum phl_role_susp_rsn rsn) { u8 map = 0; switch (rsn) { #ifdef CONFIG_WOWLAN case PHL_ROLE_SUSPEND_RSN_WOW: map = phl_get_wow_excld_susp_role_map(phl_i); break; #endif /* CONFIG_WOWLAN */ case PHL_ROLE_SUSPEND_RSN_DEV_SUSP: case PHL_ROLE_SUSPEND_RSN_RF_OFF: case PHL_ROLE_SUSPEND_RSN_MAX: default: break; } PHL_INFO("%s map(0x%x)\n", __func__, map); return map; } enum rtw_phl_status phl_role_recover(struct phl_info_t *phl_info) { u8 role_idx; struct rtw_wifi_role_t *wrole; struct rtw_phl_mld_t *mld; enum rtw_phl_status pstatus; for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) { wrole = phl_get_wrole_by_ridx(phl_info, role_idx); if (wrole == NULL) continue; if (!TEST_STATUS_FLAG(wrole->status, WR_STATUS_SUSPEND) && !TEST_STATUS_FLAG(wrole->status, WR_STATUS_HW_ALLOC_FAIL)) continue; PHL_INFO("%s with role_idx %d status 0x%x\n", __func__, role_idx, wrole->status); mld = rtw_phl_get_mld_self(phl_info, wrole); if (mld == NULL) { PHL_ERR("%s rid(%d), Failed to get self MLD\n", __func__, role_idx); continue; } pstatus = _phl_wifi_role_start(phl_info, wrole, mld); if (pstatus != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s wifi role start failed\n", __func__); return RTW_PHL_STATUS_FAILURE; } if (wrole->target_type != PHL_RTYPE_NONE) { PHL_INFO("%s with role_idx %d change to role type %d\n", __func__, role_idx, wrole->target_type); phl_wifi_role_change(phl_info, wrole, NULL, WR_CHG_TYPE, (u8 *)&wrole->target_type); wrole->target_type = PHL_RTYPE_NONE; } CLEAR_STATUS_FLAG(wrole->status, WR_STATUS_SUSPEND | WR_STATUS_HW_ALLOC_FAIL); } return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status phl_cmd_role_recover(struct phl_info_t *phl_info) { enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE; #ifdef DBG_MONITOR_TIME u32 start_t = 0; PHL_FUN_MON_START(&start_t); #endif /* DBG_MONITOR_TIME */ #ifdef CONFIG_CMD_DISP pstatus = phl_cmd_enqueue(phl_info, HW_BAND_0, MSG_EVT_ROLE_RECOVER, NULL, 0, NULL, PHL_CMD_WAIT, 0); if (is_cmd_failure(pstatus)) { /* Send cmd success, but wait cmd fail*/ pstatus = RTW_PHL_STATUS_FAILURE; } else if (pstatus != RTW_PHL_STATUS_SUCCESS) { /* Send cmd fail */ pstatus = RTW_PHL_STATUS_FAILURE; } #else pstatus = phl_role_recover(phl_info); #endif #ifdef DBG_MONITOR_TIME PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_ROLE_RECOVER); #endif /* DBG_MONITOR_TIME */ return pstatus; } static void _phl_role_suspend_done(void *drv_priv, u8 *cmd, u32 cmd_len, enum rtw_phl_status status) { if (cmd) { _os_kmem_free(drv_priv, cmd, cmd_len); cmd = NULL; PHL_INFO("%s.....\n", __func__); } } enum rtw_phl_status phl_role_suspend(struct phl_info_t *phl_info, enum phl_role_susp_rsn rsn) { u8 role_idx; struct rtw_wifi_role_t *wrole; enum rtw_phl_status pstatus; u8 excld_map = 0; excld_map = _phl_get_excld_susp_role_map(phl_info, rsn); for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) { wrole = phl_get_wrole_by_ridx(phl_info, role_idx); if (wrole == NULL || !wrole->active) continue; if (excld_map & BIT(wrole->id)) continue; PHL_INFO("%s with role_idx %d\n", __func__, role_idx); pstatus = _phl_wifi_role_stop(phl_info, wrole); SET_STATUS_FLAG(wrole->status, WR_STATUS_SUSPEND); if (pstatus != RTW_PHL_STATUS_SUCCESS) { PHL_ERR("%s wifi role stop failed\n", __func__); return RTW_PHL_STATUS_FAILURE; } } return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status phl_cmd_role_suspend(struct phl_info_t *phl_info, enum phl_role_susp_rsn rsn) { enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE; #ifdef CONFIG_CMD_DISP enum phl_role_susp_rsn *param = NULL; u32 param_len; #ifdef DBG_MONITOR_TIME u32 start_t = 0; PHL_FUN_MON_START(&start_t); #endif /* DBG_MONITOR_TIME */ param_len = sizeof(enum phl_role_susp_rsn); param = _os_kmem_alloc(phl_to_drvpriv(phl_info), param_len); if (param == NULL) { PHL_ERR("%s: alloc param failed!\n", __func__); goto _exit; } _os_mem_cpy(phl_to_drvpriv(phl_info), param, &rsn, param_len); pstatus = phl_cmd_enqueue(phl_info, HW_BAND_0, MSG_EVT_ROLE_SUSPEND, (u8 *)param, param_len, _phl_role_suspend_done, PHL_CMD_WAIT, 0); if (is_cmd_failure(pstatus)) { /* Send cmd success, but wait cmd fail*/ pstatus = RTW_PHL_STATUS_FAILURE; } else if (pstatus != RTW_PHL_STATUS_SUCCESS) { /* Send cmd fail */ _os_kmem_free(phl_to_drvpriv(phl_info), param, param_len); pstatus = RTW_PHL_STATUS_FAILURE; } _exit: #ifdef DBG_MONITOR_TIME PHL_FUNC_MON_END(phl_info->phl_com, &start_t, TIME_PHL_ROLE_SUSPEND); #endif /* DBG_MONITOR_TIME */ #else pstatus = phl_role_suspend(phl_info, rsn); #endif return pstatus; } u16 phl_role_get_bcn_intvl(struct phl_info_t *phl, struct rtw_wifi_role_t *wrole, struct rtw_wifi_role_link_t *rlink) { u16 bcn_intvl = 0; #ifdef RTW_PHL_BCN if (rtw_phl_role_is_ap_category(wrole)) { bcn_intvl = (u16)rlink->bcn_cmn.bcn_interval; } else #endif if (rtw_phl_role_is_client_category(wrole)) { struct rtw_phl_stainfo_t *sta = rtw_phl_get_stainfo_self(phl, rlink); bcn_intvl = sta->asoc_cap.bcn_interval; } else { PHL_WARN("%s() Unknown category, role id(%d), rlink(%d), type(%d)\n", __func__, wrole->id, rlink->id, wrole->type); } return bcn_intvl; } enum rtw_phl_status phl_wifi_role_macid_all_pause(struct phl_info_t *phl_info, struct rtw_wifi_role_t *wrole, bool pause) { enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS; enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS; u8 mutli_macid = false; switch (wrole->type) { case PHL_RTYPE_NONE: case PHL_RTYPE_STATION: case PHL_RTYPE_ADHOC: case PHL_RTYPE_P2P_DEVICE: case PHL_RTYPE_P2P_GC: mutli_macid = false; break; default: mutli_macid = true; break; } if (mutli_macid) { void *drv = phl_to_drvpriv(phl_info); struct macid_ctl_t *mctrl = phl_to_mac_ctrl(phl_info); u32 macid_pause[PHL_MACID_MAX_ARRAY_NUM] = {0}; _os_spinlock(phl_to_drvpriv(phl_info), &mctrl->lock, _bh, NULL); _os_mem_cpy(drv, macid_pause, &mctrl->wifi_role_usedmap[wrole->id][0], PHL_MACID_MAX_ARRAY_NUM); _os_spinunlock(phl_to_drvpriv(phl_info), &mctrl->lock, _bh, NULL); hstatus = rtw_hal_set_macid_grp_pause(phl_info->hal, macid_pause, PHL_MACID_MAX_ARRAY_NUM, pause); if (hstatus != RTW_HAL_STATUS_SUCCESS) { PHL_INFO("%s fail(hstatus=%d)\n", __func__, hstatus); pstatus = RTW_PHL_STATUS_FAILURE; } } else { struct rtw_phl_mld_t *self_mld = rtw_phl_get_mld_self((void *)phl_info, wrole); struct rtw_phl_stainfo_t *self_sta = NULL; u8 idx = 0; for (idx = 0; idx < wrole->rlink_num; idx++) { self_sta = self_mld->phl_sta[idx]; hstatus = rtw_hal_set_macid_pause(phl_info->hal, self_sta->macid, pause); if (hstatus != RTW_HAL_STATUS_SUCCESS) { PHL_INFO("%s fail(hstatus=%d)\n", __func__, hstatus); pstatus = RTW_PHL_STATUS_FAILURE; } } } return pstatus; } enum rtw_phl_status phl_get_cur_tsf(void *phl, struct rtw_phl_port_tsf *tsf) { enum rtw_hal_status hstatus = RTW_HAL_STATUS_FAILURE; struct phl_info_t *phl_info = (struct phl_info_t *)phl; hstatus = rtw_hal_get_tsf(phl_info->hal, tsf->hwband, tsf->port, &tsf->tsf_h, &tsf->tsf_l); if (RTW_HAL_STATUS_SUCCESS == hstatus) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } enum rtw_phl_status rtl_phl_cmd_get_cur_tsf(void *phl, struct rtw_phl_port_tsf *tsf, struct rtw_wifi_role_link_t *rlink, enum phl_cmd_type cmd_type, u32 cmd_timeout) { struct phl_info_t *phl_info = (struct phl_info_t *)phl; enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE; u8 hw_band = rlink->hw_band; u8 hw_port = rlink->hw_port; tsf->port = hw_port; #ifdef CONFIG_CMD_DISP if (cmd_type == PHL_CMD_DIRECTLY) { psts = phl_get_cur_tsf(phl_info, tsf); return psts; } psts = phl_cmd_enqueue(phl_info, hw_band, MSG_EVT_GET_CUR_TSF, (u8*)tsf, sizeof(struct rtw_phl_port_tsf), 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) { /* Send cmd fail */ psts = RTW_PHL_STATUS_FAILURE; } #else psts = phl_get_cur_tsf(phl_info, tsf); #endif return psts; }