diff options
author | Kuan-Chung Chen <damon.chen@realtek.com> | 2025-04-30 13:51:57 +0800 |
---|---|---|
committer | Ping-Ke Shih <pkshih@realtek.com> | 2025-05-05 10:24:21 +0800 |
commit | 02eb1aff6fde3cb4469f37aec3c55df447ecceb1 (patch) | |
tree | 1022230ab7d1e87f0b1d98efa90e2eaf57f480d0 | |
parent | d31c42466b1a3fa5766252815f2a930636131514 (diff) |
wifi: rtw89: constrain TX power according to dynamic antenna power table
Dynamic Antenna Gain (DAG) adjusts TX power based on antenna gain. To
prevent signal distortion from excessive power increases, a dynamic
antenna power table limits the maximum adjustable TX power.
Signed-off-by: Kuan-Chung Chen <damon.chen@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250430055157.13623-3-pkshih@realtek.com
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/core.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/fw.c | 76 | ||||
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/fw.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/phy.c | 84 |
4 files changed, 150 insertions, 26 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 20c0bab2600a..dfc578ad8c64 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3989,7 +3989,11 @@ struct rtw89_rfe_parms { struct rtw89_txpwr_rule_2ghz rule_2ghz; struct rtw89_txpwr_rule_5ghz rule_5ghz; struct rtw89_txpwr_rule_6ghz rule_6ghz; + struct rtw89_txpwr_rule_2ghz rule_da_2ghz; + struct rtw89_txpwr_rule_5ghz rule_da_5ghz; + struct rtw89_txpwr_rule_6ghz rule_da_6ghz; struct rtw89_tx_shape tx_shape; + bool has_da; }; struct rtw89_rfe_parms_conf { @@ -4084,9 +4088,15 @@ struct rtw89_rfe_data { struct rtw89_txpwr_lmt_2ghz_data lmt_2ghz; struct rtw89_txpwr_lmt_5ghz_data lmt_5ghz; struct rtw89_txpwr_lmt_6ghz_data lmt_6ghz; + struct rtw89_txpwr_lmt_2ghz_data da_lmt_2ghz; + struct rtw89_txpwr_lmt_5ghz_data da_lmt_5ghz; + struct rtw89_txpwr_lmt_6ghz_data da_lmt_6ghz; struct rtw89_txpwr_lmt_ru_2ghz_data lmt_ru_2ghz; struct rtw89_txpwr_lmt_ru_5ghz_data lmt_ru_5ghz; struct rtw89_txpwr_lmt_ru_6ghz_data lmt_ru_6ghz; + struct rtw89_txpwr_lmt_ru_2ghz_data da_lmt_ru_2ghz; + struct rtw89_txpwr_lmt_ru_5ghz_data da_lmt_ru_5ghz; + struct rtw89_txpwr_lmt_ru_6ghz_data da_lmt_ru_6ghz; struct rtw89_tx_shape_lmt_data tx_shape_lmt; struct rtw89_tx_shape_lmt_ru_data tx_shape_lmt_ru; struct rtw89_rfe_parms rfe_parms; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4a6455555dae..23f4dea64dc6 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1301,6 +1301,18 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = { rtw89_fw_recognize_txpwr_from_elm, { .offset = offsetof(struct rtw89_rfe_data, lmt_6ghz.conf) }, NULL, }, + [RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_2GHZ] = { + rtw89_fw_recognize_txpwr_from_elm, + { .offset = offsetof(struct rtw89_rfe_data, da_lmt_2ghz.conf) }, NULL, + }, + [RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_5GHZ] = { + rtw89_fw_recognize_txpwr_from_elm, + { .offset = offsetof(struct rtw89_rfe_data, da_lmt_5ghz.conf) }, NULL, + }, + [RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_6GHZ] = { + rtw89_fw_recognize_txpwr_from_elm, + { .offset = offsetof(struct rtw89_rfe_data, da_lmt_6ghz.conf) }, NULL, + }, [RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_2GHZ] = { rtw89_fw_recognize_txpwr_from_elm, { .offset = offsetof(struct rtw89_rfe_data, lmt_ru_2ghz.conf) }, NULL, @@ -1313,6 +1325,18 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = { rtw89_fw_recognize_txpwr_from_elm, { .offset = offsetof(struct rtw89_rfe_data, lmt_ru_6ghz.conf) }, NULL, }, + [RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_2GHZ] = { + rtw89_fw_recognize_txpwr_from_elm, + { .offset = offsetof(struct rtw89_rfe_data, da_lmt_ru_2ghz.conf) }, NULL, + }, + [RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_5GHZ] = { + rtw89_fw_recognize_txpwr_from_elm, + { .offset = offsetof(struct rtw89_rfe_data, da_lmt_ru_5ghz.conf) }, NULL, + }, + [RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_6GHZ] = { + rtw89_fw_recognize_txpwr_from_elm, + { .offset = offsetof(struct rtw89_rfe_data, da_lmt_ru_6ghz.conf) }, NULL, + }, [RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT] = { rtw89_fw_recognize_txpwr_from_elm, { .offset = offsetof(struct rtw89_rfe_data, tx_shape_lmt.conf) }, NULL, @@ -9319,6 +9343,26 @@ void rtw89_fw_load_tx_shape_lmt_ru(struct rtw89_tx_shape_lmt_ru_data *data) } } +static bool rtw89_fw_has_da_txpwr_table(struct rtw89_dev *rtwdev, + const struct rtw89_rfe_parms *parms) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->support_bands & BIT(NL80211_BAND_2GHZ) && + !(parms->rule_da_2ghz.lmt && parms->rule_da_2ghz.lmt_ru)) + return false; + + if (chip->support_bands & BIT(NL80211_BAND_5GHZ) && + !(parms->rule_da_5ghz.lmt && parms->rule_da_5ghz.lmt_ru)) + return false; + + if (chip->support_bands & BIT(NL80211_BAND_6GHZ) && + !(parms->rule_da_6ghz.lmt && parms->rule_da_6ghz.lmt_ru)) + return false; + + return true; +} + const struct rtw89_rfe_parms * rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev, const struct rtw89_rfe_parms *init) @@ -9355,6 +9399,21 @@ rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev, parms->rule_6ghz.lmt = &rfe_data->lmt_6ghz.v; } + if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_2ghz.conf)) { + rtw89_fw_load_txpwr_lmt_2ghz(&rfe_data->da_lmt_2ghz); + parms->rule_da_2ghz.lmt = &rfe_data->da_lmt_2ghz.v; + } + + if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_5ghz.conf)) { + rtw89_fw_load_txpwr_lmt_5ghz(&rfe_data->da_lmt_5ghz); + parms->rule_da_5ghz.lmt = &rfe_data->da_lmt_5ghz.v; + } + + if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_6ghz.conf)) { + rtw89_fw_load_txpwr_lmt_6ghz(&rfe_data->da_lmt_6ghz); + parms->rule_da_6ghz.lmt = &rfe_data->da_lmt_6ghz.v; + } + if (rtw89_txpwr_conf_valid(&rfe_data->lmt_ru_2ghz.conf)) { rtw89_fw_load_txpwr_lmt_ru_2ghz(&rfe_data->lmt_ru_2ghz); parms->rule_2ghz.lmt_ru = &rfe_data->lmt_ru_2ghz.v; @@ -9370,6 +9429,21 @@ rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev, parms->rule_6ghz.lmt_ru = &rfe_data->lmt_ru_6ghz.v; } + if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_ru_2ghz.conf)) { + rtw89_fw_load_txpwr_lmt_ru_2ghz(&rfe_data->da_lmt_ru_2ghz); + parms->rule_da_2ghz.lmt_ru = &rfe_data->da_lmt_ru_2ghz.v; + } + + if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_ru_5ghz.conf)) { + rtw89_fw_load_txpwr_lmt_ru_5ghz(&rfe_data->da_lmt_ru_5ghz); + parms->rule_da_5ghz.lmt_ru = &rfe_data->da_lmt_ru_5ghz.v; + } + + if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_ru_6ghz.conf)) { + rtw89_fw_load_txpwr_lmt_ru_6ghz(&rfe_data->da_lmt_ru_6ghz); + parms->rule_da_6ghz.lmt_ru = &rfe_data->da_lmt_ru_6ghz.v; + } + if (rtw89_txpwr_conf_valid(&rfe_data->tx_shape_lmt.conf)) { rtw89_fw_load_tx_shape_lmt(&rfe_data->tx_shape_lmt); parms->tx_shape.lmt = &rfe_data->tx_shape_lmt.v; @@ -9380,5 +9454,7 @@ rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev, parms->tx_shape.lmt_ru = &rfe_data->tx_shape_lmt_ru.v; } + parms->has_da = rtw89_fw_has_da_txpwr_table(rtwdev, parms); + return parms; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index bb1b653085cf..559f3f6190eb 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3908,6 +3908,12 @@ enum rtw89_fw_element_id { RTW89_FW_ELEMENT_ID_TXPWR_TRK = 18, RTW89_FW_ELEMENT_ID_RFKLOG_FMT = 19, RTW89_FW_ELEMENT_ID_REGD = 20, + RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_2GHZ = 21, + RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_5GHZ = 22, + RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_6GHZ = 23, + RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_2GHZ = 24, + RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_5GHZ = 25, + RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_6GHZ = 26, RTW89_FW_ELEMENT_ID_NUM, }; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index e358cb83dae8..76a2e26d4a10 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2034,19 +2034,10 @@ static s8 rtw89_phy_ant_gain_query(struct rtw89_dev *rtwdev, ant_gain->offset[path][subband_h]); } -static s8 rtw89_phy_ant_gain_offset(struct rtw89_dev *rtwdev, u8 band, u32 center_freq) +static s8 rtw89_phy_ant_gain_offset(struct rtw89_dev *rtwdev, u32 center_freq) { - struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain; - const struct rtw89_chip_info *chip = rtwdev->chip; - u8 regd = rtw89_regd_get(rtwdev, band); s8 offset_patha, offset_pathb; - if (!chip->support_ant_gain) - return 0; - - if (ant_gain->block_country || !(ant_gain->regd_enabled & BIT(regd))) - return 0; - offset_patha = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_A, center_freq); offset_pathb = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_B, center_freq); @@ -2056,18 +2047,31 @@ static s8 rtw89_phy_ant_gain_offset(struct rtw89_dev *rtwdev, u8 band, u32 cente return max(offset_patha, offset_pathb); } -s16 rtw89_phy_ant_gain_pwr_offset(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan) +static bool rtw89_can_apply_ant_gain(struct rtw89_dev *rtwdev, u8 band) { + const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms; struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain; const struct rtw89_chip_info *chip = rtwdev->chip; - u8 regd = rtw89_regd_get(rtwdev, chan->band_type); - s8 offset_patha, offset_pathb; + u8 regd = rtw89_regd_get(rtwdev, band); if (!chip->support_ant_gain) - return 0; + return false; if (ant_gain->block_country || !(ant_gain->regd_enabled & BIT(regd))) + return false; + + if (!rfe_parms->has_da) + return false; + + return true; +} + +s16 rtw89_phy_ant_gain_pwr_offset(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + s8 offset_patha, offset_pathb; + + if (!rtw89_can_apply_ant_gain(rtwdev, chan->band_type)) return 0; if (RTW89_CHK_FW_FEATURE(NO_POWER_DIFFERENCE, &rtwdev->fw)) @@ -2083,14 +2087,10 @@ EXPORT_SYMBOL(rtw89_phy_ant_gain_pwr_offset); int rtw89_print_ant_gain(struct rtw89_dev *rtwdev, char *buf, size_t bufsz, const struct rtw89_chan *chan) { - struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain; - const struct rtw89_chip_info *chip = rtwdev->chip; - u8 regd = rtw89_regd_get(rtwdev, chan->band_type); char *p = buf, *end = buf + bufsz; s8 offset_patha, offset_pathb; - if (!(chip->support_ant_gain && (ant_gain->regd_enabled & BIT(regd))) || - ant_gain->block_country) { + if (!rtw89_can_apply_ant_gain(rtwdev, chan->band_type)) { p += scnprintf(p, end - p, "no DAG is applied\n"); goto out; } @@ -2255,24 +2255,31 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, u8 bw, u8 ntx, u8 rs, u8 bf, u8 ch) { const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms; + const struct rtw89_txpwr_rule_2ghz *rule_da_2ghz = &rfe_parms->rule_da_2ghz; + const struct rtw89_txpwr_rule_5ghz *rule_da_5ghz = &rfe_parms->rule_da_5ghz; + const struct rtw89_txpwr_rule_6ghz *rule_da_6ghz = &rfe_parms->rule_da_6ghz; const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz; const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz; const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz; struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band); + bool has_ant_gain = rtw89_can_apply_ant_gain(rtwdev, band); u32 freq = ieee80211_channel_to_frequency(ch, nl_band); u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch); + s8 lmt = 0, da_lmt = S8_MAX, sar, offset = 0; u8 regd = rtw89_regd_get(rtwdev, band); u8 reg6 = regulatory->reg_6ghz_power; struct rtw89_sar_parm sar_parm = { .center_freq = freq, .ntx = ntx, }; - s8 lmt = 0, sar, offset; s8 cstr; switch (band) { case RTW89_BAND_2G: + if (has_ant_gain) + da_lmt = (*rule_da_2ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx]; + lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx]; if (lmt) break; @@ -2280,6 +2287,9 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx]; break; case RTW89_BAND_5G: + if (has_ant_gain) + da_lmt = (*rule_da_5ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx]; + lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx]; if (lmt) break; @@ -2287,6 +2297,9 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx]; break; case RTW89_BAND_6G: + if (has_ant_gain) + da_lmt = (*rule_da_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx]; + lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx]; if (lmt) break; @@ -2300,8 +2313,11 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, return 0; } - offset = rtw89_phy_ant_gain_offset(rtwdev, band, freq); - lmt = rtw89_phy_txpwr_rf_to_mac(rtwdev, lmt + offset); + da_lmt = da_lmt ?: S8_MAX; + if (da_lmt != S8_MAX) + offset = rtw89_phy_ant_gain_offset(rtwdev, freq); + + lmt = rtw89_phy_txpwr_rf_to_mac(rtwdev, min(lmt + offset, da_lmt)); sar = rtw89_query_sar(rtwdev, &sar_parm); cstr = rtw89_phy_get_tpe_constraint(rtwdev, band); @@ -2519,24 +2535,31 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, u8 ru, u8 ntx, u8 ch) { const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms; + const struct rtw89_txpwr_rule_2ghz *rule_da_2ghz = &rfe_parms->rule_da_2ghz; + const struct rtw89_txpwr_rule_5ghz *rule_da_5ghz = &rfe_parms->rule_da_5ghz; + const struct rtw89_txpwr_rule_6ghz *rule_da_6ghz = &rfe_parms->rule_da_6ghz; const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz; const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz; const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz; struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band); + bool has_ant_gain = rtw89_can_apply_ant_gain(rtwdev, band); u32 freq = ieee80211_channel_to_frequency(ch, nl_band); u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch); + s8 lmt_ru = 0, da_lmt_ru = S8_MAX, sar, offset = 0; u8 regd = rtw89_regd_get(rtwdev, band); u8 reg6 = regulatory->reg_6ghz_power; struct rtw89_sar_parm sar_parm = { .center_freq = freq, .ntx = ntx, }; - s8 lmt_ru = 0, sar, offset; s8 cstr; switch (band) { case RTW89_BAND_2G: + if (has_ant_gain) + da_lmt_ru = (*rule_da_2ghz->lmt_ru)[ru][ntx][regd][ch_idx]; + lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][regd][ch_idx]; if (lmt_ru) break; @@ -2544,6 +2567,9 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx]; break; case RTW89_BAND_5G: + if (has_ant_gain) + da_lmt_ru = (*rule_da_5ghz->lmt_ru)[ru][ntx][regd][ch_idx]; + lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][regd][ch_idx]; if (lmt_ru) break; @@ -2551,6 +2577,9 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx]; break; case RTW89_BAND_6G: + if (has_ant_gain) + da_lmt_ru = (*rule_da_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx]; + lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx]; if (lmt_ru) break; @@ -2564,8 +2593,11 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, return 0; } - offset = rtw89_phy_ant_gain_offset(rtwdev, band, freq); - lmt_ru = rtw89_phy_txpwr_rf_to_mac(rtwdev, lmt_ru + offset); + da_lmt_ru = da_lmt_ru ?: S8_MAX; + if (da_lmt_ru != S8_MAX) + offset = rtw89_phy_ant_gain_offset(rtwdev, freq); + + lmt_ru = rtw89_phy_txpwr_rf_to_mac(rtwdev, min(lmt_ru + offset, da_lmt_ru)); sar = rtw89_query_sar(rtwdev, &sar_parm); cstr = rtw89_phy_get_tpe_constraint(rtwdev, band); |