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

Bug 4667769
Bug 4667981

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

520 lines
17 KiB
C

/******************************************************************************
*
* Copyright(c) 2019 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*****************************************************************************/
#define _PHL_DFS_C_
#include "phl_headers.h"
#ifdef CONFIG_PHL_DFS
struct dfs_rd_ctl_param {
/*
* DFS region domain set from core
* >=DFS_REGD_NUM => not set (keep original)
* < DFS_REGD_NUM => change domain (if needed) and ignore other parameters
*/
enum dfs_regd_t domain;
/*
* enable=true, cac=1 => enable radar detect and is under CAC
* enable=true, cac=0 => enalbe radar detect, in-service monitoring
* enable=true, cac<0 => enable radar detect w/o changing CAC status
* enable=false, cac=any => disable radar detect
*/
bool enable;
/*
* CAC status set from core
* < 0: not set (keep original)
* 0: not under CAC
* 1: under CAC
*/
s8 cac;
/*
* configuration for specific radar detect range (5G band is implicit), the value of sp_ch:
* < 0: not set (keep original)
* 0: all detectable range
* > 0: specific detect range (by ch, bw, offset)
*/
s16 sp_ch;
enum channel_width sp_bw;
enum chan_offset sp_offset;
/*
* configuration for specific radar detect range in freqency, valid when sp_ch < 0
* 0: not set (keep original)
*/
u32 sp_freq_hi;
u32 sp_freq_lo;
};
static bool phl_radar_detect_range_specified(struct rtw_dfs_t *dfs_info)
{
return dfs_info->sp_detect_range_hi != 0;
}
static bool phl_overlap_radar_detect_range(struct rtw_dfs_t *dfs_info
, enum band_type band, u8 ch, enum channel_width bw, enum chan_offset offset)
{
bool ret = false;
u32 hi = 0, lo = 0;
int i;
if (!rtw_phl_bchbw_to_freq_range(band, ch, bw, offset, &hi, &lo)) {
_os_warn_on(1);
goto exit;
}
if (RANGE_OVERLAP(hi, lo, dfs_info->sp_detect_range_hi, dfs_info->sp_detect_range_lo))
ret = true;
exit:
return ret;
}
static bool phl_should_radar_detect_enable_by_ch(struct phl_info_t *phl_info, u8 band_idx,
enum band_type band, u8 channel, enum channel_width bwmode, enum chan_offset offset)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_dfs_t *dfs_info = &phl_com->dfs_info;
if (dfs_info->enable && !PHL_DFS_REGD_IS_UNKNOWN(dfs_info->region_domain)
&& rtw_hal_in_radar_domain(phl_info->hal, band, channel, bwmode, offset)
) {
if (!phl_radar_detect_range_specified(dfs_info)
|| phl_overlap_radar_detect_range(dfs_info, band, channel, bwmode, offset))
return true;
}
return false;
}
static void phl_dfs_handle_pending_domain_change(struct phl_info_t *phl_info, u8 band_idx
, enum band_type band, u8 ch, enum channel_width bw, enum chan_offset offset)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_dfs_t *dfs_info = &phl_com->dfs_info;
if (dfs_info->pending_domain_change) {
rtw_hal_bb_dfs_change_domain(phl_info->hal, band, ch, bw, offset);
dfs_info->pending_domain_change = false;
}
}
static enum rtw_phl_status
phl_radar_detect_switch(struct phl_info_t *phl_info, u8 band_idx, bool enable)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_dfs_t *dfs_info = &phl_com->dfs_info;
if (rtw_hal_radar_detect_cfg(phl_info->hal, band_idx, enable) == RTW_HAL_STATUS_SUCCESS) {
dfs_info->radar_detect_enabled = enable;
return RTW_PHL_STATUS_SUCCESS;
}
return RTW_PHL_STATUS_FAILURE;
}
bool rtw_phl_is_radar_detect_enabled(struct rtw_phl_com_t *phl_com, u8 band_idx)
{
return phl_com->dfs_info.radar_detect_enabled;
}
static void phl_set_under_cac(struct phl_info_t *phl_info, u8 band_idx, bool under)
{
if (under)
SET_STATUS_FLAG(phl_info->phl_com->dev_state, RTW_DEV_IN_DFS_CAC_PERIOD);
else
CLEAR_STATUS_FLAG(phl_info->phl_com->dev_state, RTW_DEV_IN_DFS_CAC_PERIOD);
}
bool rtw_phl_is_under_cac(struct rtw_phl_com_t *phl_com, u8 band_idx)
{
return TEST_STATUS_FLAG(phl_com->dev_state, RTW_DEV_IN_DFS_CAC_PERIOD);
}
static enum rtw_phl_status
phl_cac_tx_pause_switch(struct phl_info_t *phl_info, u8 band_idx, bool enable)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_dfs_t *dfs_info = &phl_com->dfs_info;
if (rtw_hal_dfs_pause_tx(phl_info->hal, band_idx, enable, PAUSE_RSON_DFS_CAC) == RTW_HAL_STATUS_SUCCESS) {
dfs_info->cac_tx_paused = enable;
return RTW_PHL_STATUS_SUCCESS;
}
return RTW_PHL_STATUS_FAILURE;
}
bool phl_is_cac_tx_paused(struct phl_info_t *phl_info, u8 band_idx)
{
return phl_info->phl_com->dfs_info.cac_tx_paused;
}
void phl_dfs_rd_setting_before_ch_switch(struct phl_info_t *phl_info, u8 band_idx
, enum band_type band, u8 ch, enum channel_width bw, enum chan_offset offset, struct dfs_rd_ch_switch_ctx *ctx)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
ctx->should_rd_en_on_new_ch = phl_should_radar_detect_enable_by_ch(phl_info
, band_idx, band, ch, bw, offset);
ctx->under_cac = rtw_phl_is_under_cac(phl_com, band_idx);
ctx->cac_tx_paused = phl_is_cac_tx_paused(phl_info, band_idx);
ctx->rd_enabled = rtw_phl_is_radar_detect_enabled(phl_com, band_idx);
if (!ctx->should_rd_en_on_new_ch && ctx->rd_enabled) {
/* turn off radar detect before channel setting (ex: leaving detection range) */
enum rtw_phl_status rst = phl_radar_detect_switch(phl_info, band_idx, false);
PHL_TRACE(COMP_PHL_DBG, (rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] new ch=%d,%u,%d,%d disable radar detect%s\n"
, band, ch, bw, offset, rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
ctx->rd_enabled = rtw_phl_is_radar_detect_enabled(phl_com, band_idx);
}
if (ctx->should_rd_en_on_new_ch && ctx->under_cac && !ctx->cac_tx_paused) {
/* turn on CAC tx pause before channel setting (ex: entering detection range) */
enum rtw_phl_status rst = phl_cac_tx_pause_switch(phl_info, band_idx, true);
PHL_TRACE(COMP_PHL_DBG, (rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] new ch=%d,%u,%d,%d enable CAC tx pause%s\n"
, band, ch, bw, offset, rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
}
}
void phl_dfs_rd_setting_after_ch_switch(struct phl_info_t *phl_info, u8 band_idx
, enum band_type band, u8 ch, enum channel_width bw, enum chan_offset offset, struct dfs_rd_ch_switch_ctx *ctx)
{
if (ctx->should_rd_en_on_new_ch && !ctx->rd_enabled) {
/* turn on radar detect after channel setting (ex: entered radar detect range) */
enum rtw_phl_status rst = phl_radar_detect_switch(phl_info, band_idx, true);
PHL_TRACE(COMP_PHL_DBG, (rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] new ch=%d,%u,%d,%d enable radar detect%s\n"
, band, ch, bw, offset, rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
}
if ((!ctx->should_rd_en_on_new_ch || !ctx->under_cac) && ctx->cac_tx_paused) {
/* turn off CAC tx pause after channel setting (ex: leaved detection range) */
enum rtw_phl_status rst = phl_cac_tx_pause_switch(phl_info, band_idx, false);
PHL_TRACE(COMP_PHL_DBG, (rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] new ch=%d,%u,%d,%d disable CAC tx pause%s\n"
, band, ch, bw, offset, rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
}
}
static enum rtw_phl_status
phl_radar_detect_confs_apply(struct phl_info_t *phl_info, u8 band_idx)
{
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_dfs_t *dfs_info = &phl_com->dfs_info;
enum rtw_phl_status rd_rst = RTW_PHL_STATUS_SUCCESS;
enum rtw_phl_status cac_rst = RTW_PHL_STATUS_SUCCESS;
struct rtw_chan_def chdef;
bool should_rd_enable;
bool under_cac;
bool cac_tx_paused;
rtw_hal_get_cur_chdef(phl_info->hal, band_idx, &chdef);
phl_dfs_handle_pending_domain_change(phl_info, band_idx
, chdef.band, chdef.chan, chdef.bw, chdef.offset);
should_rd_enable = phl_should_radar_detect_enable_by_ch(phl_info, band_idx
, chdef.band, chdef.chan, chdef.bw, chdef.offset);
under_cac = rtw_phl_is_under_cac(phl_com, band_idx);
cac_tx_paused = phl_is_cac_tx_paused(phl_info, band_idx);
if (!dfs_info->radar_detect_enabled) {
if (should_rd_enable) {
rd_rst = phl_radar_detect_switch(phl_info, band_idx, true);
PHL_TRACE(COMP_PHL_DBG, (rd_rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] ch=%d,%u,%d,%d enable radar detect%s\n"
, chdef.band, chdef.chan, chdef.bw, chdef.offset
, rd_rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
}
} else if (dfs_info->radar_detect_enabled) {
if (!should_rd_enable) {
rd_rst = phl_radar_detect_switch(phl_info, band_idx, false);
PHL_TRACE(COMP_PHL_DBG, (rd_rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] ch=%d,%u,%d,%d disable radar detect%s\n"
, chdef.band, chdef.chan, chdef.bw, chdef.offset
, rd_rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
}
}
if (!cac_tx_paused) {
if (under_cac && dfs_info->radar_detect_enabled) {
cac_rst = phl_cac_tx_pause_switch(phl_info, band_idx, true);
PHL_TRACE(COMP_PHL_DBG, (cac_rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] ch=%d,%u,%d,%d enable CAC tx pause%s\n"
, chdef.band, chdef.chan, chdef.bw, chdef.offset
, cac_rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
}
} else if (cac_tx_paused) {
if (!under_cac) {
/*
* Release CAC tx pause only when not under CAC
* Keep CAC tx pause when under CAC and radar detect is turned off by
* specifying new detect range which doesn't overlap current channel setting
* (ex: operating channel switching to new DFS channel)
*/
cac_rst = phl_cac_tx_pause_switch(phl_info, band_idx, false);
PHL_TRACE(COMP_PHL_DBG, (cac_rst == RTW_PHL_STATUS_SUCCESS ? _PHL_INFO_ : _PHL_ERR_)
, "[DFS] ch=%d,%u,%d,%d disable CAC tx pause%s\n"
, chdef.band, chdef.chan, chdef.bw, chdef.offset
, cac_rst != RTW_PHL_STATUS_SUCCESS ? " failed" : "");
}
}
if (rd_rst == RTW_PHL_STATUS_SUCCESS && cac_rst == RTW_PHL_STATUS_SUCCESS)
return RTW_PHL_STATUS_SUCCESS;
return RTW_PHL_STATUS_FAILURE;
}
static enum rtw_phl_status
_phl_dfs_rd_ctl_hdl(void *phl, u8 *param)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct rtw_phl_com_t *phl_com = phl_info->phl_com;
struct rtw_dfs_t *dfs_info = &phl_com->dfs_info;
struct dfs_rd_ctl_param *rd_ctl_param = (struct dfs_rd_ctl_param *)param;
u8 band_idx = HW_BAND_0; /* multi band/phy capable? */
if (rd_ctl_param->domain < DFS_REGD_NUM) {
if (rd_ctl_param->domain != dfs_info->region_domain) {
PHL_INFO("%s set domain to %d\n", __func__, rd_ctl_param->domain);
dfs_info->region_domain = rd_ctl_param->domain;
dfs_info->pending_domain_change = true;
}
goto apply;
}
if (rd_ctl_param->enable) {
if (!dfs_info->enable) {
PHL_INFO("%s enable\n", __func__);
dfs_info->enable = true;
}
if (rd_ctl_param->cac == 1) {
if (!rtw_phl_is_under_cac(phl_com, band_idx)) {
PHL_INFO("%s under CAC\n", __func__);
phl_set_under_cac(phl_info, band_idx, true);
}
} else if (rd_ctl_param->cac == 0) {
if (rtw_phl_is_under_cac(phl_com, band_idx)) {
PHL_INFO("%s CAC done\n", __func__);
phl_set_under_cac(phl_info, band_idx, false);
}
}
} else {
if (dfs_info->enable) {
PHL_INFO("%s disable\n", __func__);
dfs_info->enable = false;
}
phl_set_under_cac(phl_info, band_idx, false);
}
if (rd_ctl_param->sp_ch > 0) {
u32 hi, lo;
if (rtw_phl_bchbw_to_freq_range(BAND_ON_5G
, rd_ctl_param->sp_ch, rd_ctl_param->sp_bw, rd_ctl_param->sp_offset
, &hi, &lo)
) {
if (dfs_info->sp_detect_range_hi != hi || dfs_info->sp_detect_range_lo != lo) {
PHL_INFO("%s sp_ch:%u,%d,%d is set\n", __func__
, rd_ctl_param->sp_ch, rd_ctl_param->sp_bw, rd_ctl_param->sp_offset);
dfs_info->sp_detect_range_hi = hi;
dfs_info->sp_detect_range_lo = lo;
}
} else {
PHL_WARN("%s sp_ch:%u,%d,%d to freq range fail, all range applied\n", __func__
, rd_ctl_param->sp_ch, rd_ctl_param->sp_bw, rd_ctl_param->sp_offset);
dfs_info->sp_detect_range_hi = 0;
}
} else if (rd_ctl_param->sp_ch == 0) {
if (dfs_info->sp_detect_range_hi != 0) {
PHL_INFO("%s all range applied\n", __func__);
dfs_info->sp_detect_range_hi = 0;
}
} else if (rd_ctl_param->sp_freq_hi) {
if (rd_ctl_param->sp_freq_hi <= rd_ctl_param->sp_freq_lo) {
PHL_WARN("%s sp_freq_hi:%u <= sp_freq_lo:%u, all range applied\n", __func__
, rd_ctl_param->sp_freq_hi, rd_ctl_param->sp_freq_lo);
} else {
if (dfs_info->sp_detect_range_hi != rd_ctl_param->sp_freq_hi
|| dfs_info->sp_detect_range_lo != rd_ctl_param->sp_freq_lo
) {
PHL_INFO("%s sp_freq %u to %u is set\n", __func__
, rd_ctl_param->sp_freq_lo, rd_ctl_param->sp_freq_hi);
dfs_info->sp_detect_range_hi = rd_ctl_param->sp_freq_hi;
dfs_info->sp_detect_range_lo = rd_ctl_param->sp_freq_lo;
}
}
}
apply:
/* apply new configs on cur channel */
return phl_radar_detect_confs_apply(phl_info, band_idx);
}
enum rtw_phl_status
phl_cmd_dfs_rd_ctl_hdl(struct phl_info_t *phl_info, u8 *param)
{
return _phl_dfs_rd_ctl_hdl(phl_info, param);
}
static void _phl_dfs_rd_ctl_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__);
}
}
static enum rtw_phl_status
_rtw_phl_cmd_dfs_rd_ctl(struct phl_info_t *phl_info, enum phl_band_idx hw_band
, enum dfs_regd_t domain, bool enable, s8 cac, s16 sp_ch, enum channel_width sp_bw, enum chan_offset sp_offset
, u32 sp_freq_hi, u32 sp_freq_lo
, enum phl_cmd_type cmd_type, u32 cmd_timeout)
{
#ifdef CONFIG_CMD_DISP
void *drv = phl_info->phl_com->drv_priv;
enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
struct dfs_rd_ctl_param *param = NULL;
u32 param_len;
param_len = sizeof(struct dfs_rd_ctl_param);
param = _os_kmem_alloc(drv, param_len);
if (param == NULL) {
PHL_ERR("%s: alloc param failed!\n", __func__);
goto _exit;
}
param->domain = domain;
param->enable = enable;
param->cac = cac;
param->sp_ch = sp_ch;
param->sp_bw = sp_bw;
param->sp_offset = sp_offset;
param->sp_freq_hi = sp_freq_hi;
param->sp_freq_lo = sp_freq_lo;
if (cmd_type == PHL_CMD_DIRECTLY) {
psts = phl_cmd_dfs_rd_ctl_hdl(phl_info, (u8 *)param);
_phl_dfs_rd_ctl_done(drv, (u8 *)param, param_len, psts);
goto _exit;
}
psts = phl_cmd_enqueue(phl_info,
hw_band,
MSG_EVT_DFS_RD_SETUP,
(u8 *)param, param_len,
_phl_dfs_rd_ctl_done,
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 */
_os_kmem_free(drv, param, param_len);
psts = RTW_PHL_STATUS_FAILURE;
}
_exit:
return psts;
#else
PHL_ERR("%s(), CONFIG_CMD_DISP need to be enabled for MSG_EVT_DFS_RD_SETUP \n",__func__);
return RTW_PHL_STATUS_FAILURE;
#endif
}
enum rtw_phl_status
rtw_phl_cmd_dfs_change_domain(void *phl_info, enum phl_band_idx hw_band
, enum dfs_regd_t domain, enum phl_cmd_type cmd_type, u32 cmd_timeout)
{
if (domain >= DFS_REGD_NUM) {
PHL_WARN("%s(), invalid domain:%d\n", __func__, domain);
return RTW_PHL_STATUS_INVALID_PARAM;
}
return _rtw_phl_cmd_dfs_rd_ctl(phl_info, hw_band
, domain /* change domain, other parameters will be ignored */
, false, 0, -1, 0, 0, 0, 0
, cmd_type, cmd_timeout);
}
enum rtw_phl_status
rtw_phl_cmd_dfs_rd_enable_all_range(void *phl_info, enum phl_band_idx hw_band
, enum phl_cmd_type cmd_type, u32 cmd_timeout)
{
return _rtw_phl_cmd_dfs_rd_ctl(phl_info, hw_band
, DFS_REGD_NUM
, true, -1 /* enable radar detect w/o changing CAC status */
, 0, 0, 0, 0, 0
, cmd_type, cmd_timeout);
}
enum rtw_phl_status
rtw_phl_cmd_dfs_rd_enable_with_sp_chbw(void *phl_info, enum phl_band_idx hw_band
, bool cac, u8 sp_ch, enum channel_width sp_bw, enum chan_offset sp_offset
, enum phl_cmd_type cmd_type, u32 cmd_timeout)
{
return _rtw_phl_cmd_dfs_rd_ctl(phl_info, hw_band
, DFS_REGD_NUM
, true, cac ? 1 : 0, sp_ch, sp_bw, sp_offset, 0, 0
, cmd_type, cmd_timeout);
}
enum rtw_phl_status
rtw_phl_cmd_dfs_rd_enable_with_sp_freq_range(void *phl_info, enum phl_band_idx hw_band
, bool cac, u32 sp_freq_hi, u32 sp_freq_lo
, enum phl_cmd_type cmd_type, u32 cmd_timeout)
{
return _rtw_phl_cmd_dfs_rd_ctl(phl_info, hw_band
, DFS_REGD_NUM
, true, cac ? 1 : 0, -1, 0, 0, sp_freq_hi, sp_freq_lo
, cmd_type, cmd_timeout);
}
enum rtw_phl_status
rtw_phl_cmd_dfs_rd_set_cac_status(void *phl_info, enum phl_band_idx hw_band
, bool cac, enum phl_cmd_type cmd_type, u32 cmd_timeout)
{
return _rtw_phl_cmd_dfs_rd_ctl(phl_info, hw_band
, DFS_REGD_NUM
, true /* CAC status only valid when radar detect enable */
, cac ? 1 : 0, -1, 0, 0, 0, 0
, cmd_type, cmd_timeout);
}
enum rtw_phl_status
rtw_phl_cmd_dfs_rd_disable(void *phl_info, enum phl_band_idx hw_band
, enum phl_cmd_type cmd_type, u32 cmd_timeout)
{
return _rtw_phl_cmd_dfs_rd_ctl(phl_info, hw_band
, DFS_REGD_NUM
, false, 0, -1, 0, 0, 0, 0
, cmd_type, cmd_timeout);
}
#endif