/******************************************************************************
|
*
|
* Copyright(c) 2020 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_THERMAL_C_
|
#include "phl_headers.h"
|
|
#ifdef CONFIG_PHL_THERMAL_PROTECT
|
|
static void _phl_thermal_protect_disable_all_txop(
|
struct phl_info_t *phl_info,
|
bool disable)
|
{
|
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 = NULL;
|
struct rtw_wifi_role_link_t *rlink = NULL;
|
struct rtw_phl_mld_t *mld = NULL;
|
struct rtw_phl_stainfo_t *sta = NULL;
|
struct rtw_edca_param edca = {0};
|
u8 i = 0;
|
u8 idx = 0;
|
|
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);
|
if(wrole){
|
if(wrole->mstate == MLME_LINKED)
|
break;
|
}
|
wrole = NULL;
|
continue;
|
}
|
}
|
|
if(wrole == NULL)
|
return;
|
|
mld = rtw_phl_get_mld_self(phl_info, wrole);
|
for (idx = 0; idx < wrole->rlink_num; idx++) {
|
rlink = get_rlink(wrole, idx);
|
sta = mld->phl_sta[idx];
|
|
if(sta == NULL)
|
return;
|
|
for(i = 0; i < 4;i++){
|
edca.ac = i;
|
edca.param = sta->asoc_cap.edca[edca.ac].param;
|
if(disable)
|
edca.param &= 0x0000FFFF;
|
|
if(rtw_hal_set_edca(phl_info->hal, rlink, edca.ac, edca.param)
|
!= RTW_HAL_STATUS_SUCCESS)
|
PHL_ERR("%s Config edca fail\n", __FUNCTION__);
|
}
|
}
|
}
|
|
static void _phl_thermal_protect_reduce_ampdu_num(
|
struct phl_info_t *phl_info,
|
u8 ratio)
|
{
|
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 = NULL;
|
struct rtw_phl_mld_t *mld = NULL;
|
struct rtw_phl_stainfo_t *sta = NULL;
|
u8 i = 0;
|
u8 idx = 0;
|
|
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);
|
if(wrole){
|
if(wrole->mstate == MLME_LINKED)
|
break;
|
}
|
wrole = NULL;
|
continue;
|
}
|
}
|
|
if(wrole == NULL)
|
return;
|
|
mld = rtw_phl_get_mld_self(phl_info, wrole);
|
for (idx = 0; idx < wrole->rlink_num; idx++) {
|
sta = mld->phl_sta[idx];
|
|
if(sta == NULL)
|
return;
|
|
if(ratio != 0){
|
if(rtw_hal_thermal_protect_cfg_tx_ampdu(phl_info->hal, sta, ratio)
|
!= RTW_HAL_STATUS_SUCCESS)
|
PHL_ERR("%s Thermal protect cfg tx ampdu fail\n", __FUNCTION__);
|
}
|
else{
|
if(sta->asoc_cap.num_ampdu_bk != 0){
|
sta->asoc_cap.num_ampdu = sta->asoc_cap.num_ampdu_bk;
|
sta->asoc_cap.num_ampdu_bk = 0;
|
}
|
if(rtw_hal_cfg_tx_ampdu(phl_info->hal, sta) !=
|
RTW_HAL_STATUS_SUCCESS)
|
PHL_ERR("%s Thermal protect restore tx ampdu fail\n", __FUNCTION__);
|
}
|
}
|
}
|
|
void phl_thermal_protect_watchdog(struct phl_info_t *phl_info)
|
{
|
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
|
bool action_changed = false;
|
u8 min_tx_duty = phl_com->dev_cap.min_tx_duty;
|
u8 next_tx_duty = THERMAL_NO_TX_DUTY_CTRL;
|
u8 duty_interval = 1;
|
|
if (min_tx_duty == THERMAL_NO_TX_DUTY_CTRL)
|
return;
|
|
if(phl_com->drv_mode != RTW_DRV_MODE_NORMAL &&
|
phl_com->drv_mode != RTW_DRV_MODE_HIGH_THERMAL)
|
return;
|
|
action_changed = rtw_hal_check_thermal_protect(phl_com, phl_info->hal);
|
|
if(action_changed == false)
|
return;
|
|
duty_interval = (THERMAL_NO_TX_DUTY_CTRL - min_tx_duty) / PHL_THERMAL_PROTECT_ACTION_LEVEL_MAX;
|
if (duty_interval == 0)
|
duty_interval = 1;
|
|
if (phl_com->thermal_protect_action == PHL_THERMAL_PROTECT_ACTION_NONE) {
|
phl_thermal_protect_stop_tx_duty(phl_info);
|
} else {
|
next_tx_duty = THERMAL_TX_DUTY_CTRL_DURATION - (duty_interval * (u8)phl_com->thermal_protect_action);
|
if (next_tx_duty >= min_tx_duty)
|
phl_thermal_protect_cfg_tx_duty(phl_info,
|
THERMAL_TX_DUTY_CTRL_DURATION,
|
next_tx_duty);
|
}
|
}
|
|
#endif /* CONFIG_PHL_THERMAL_PROTECT */
|
|
void phl_thermal_protect_cfg_tx_duty(
|
struct phl_info_t *phl_info,
|
u16 tx_duty_interval,
|
u8 ratio)
|
{
|
enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
|
|
hal_status = rtw_hal_thermal_protect_cfg_tx_duty(phl_info->hal,
|
tx_duty_interval,
|
ratio);
|
if(hal_status != RTW_HAL_STATUS_SUCCESS)
|
PHL_ERR("%s Thermal protect cfg tx duty fail\n", __FUNCTION__);
|
}
|
|
void phl_thermal_protect_stop_tx_duty(struct phl_info_t *phl_info)
|
{
|
enum rtw_hal_status hal_status = RTW_HAL_STATUS_SUCCESS;
|
|
hal_status = rtw_hal_thermal_protect_stop_tx_duty(phl_info->hal);
|
if(hal_status != RTW_HAL_STATUS_SUCCESS)
|
PHL_ERR("%s Thermal protect stop tx duty fail\n", __FUNCTION__);
|
}
|