8812a and 8814a support STBC, enable it. 8822c will lose reporting TX STBC capability if efuse reports only 1 path, but this is correct, since in that case it doesn't actually support STBC. Tested on RTL8812AU, STBC packets were captured in monitor mode. Signed-off-by: Ho Jie Feng --- drivers/net/wireless/realtek/rtw88/main.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8812a.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8814a.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f7708ad17b..e243738809 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1583,7 +1583,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, if (rtw_chip_has_rx_ldpc(rtwdev)) ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING; - if (rtw_chip_has_tx_stbc(rtwdev)) + if (rtw_chip_has_tx_stbc(rtwdev) && rtwdev->hal.rf_path_num > 1) ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; if (efuse->hw_cap.bw & BIT(RTW_CHANNEL_WIDTH_40)) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index 781b66ccde..55f1d3d324 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -1077,6 +1077,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = { .rfe_defs = rtw8812a_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8812a_rfe_defs), .rx_ldpc = false, + .tx_stbc = true, .amsdu_in_ampdu = true, .hw_feature_report = false, .c2h_ra_report_size = 4, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c index b6916d3dc6..e35c57c9d1 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c @@ -2200,6 +2200,7 @@ const struct rtw_chip_info rtw8814a_hw_spec = { .txgi_factor = 1, .is_pwr_by_rate_dec = true, .rx_ldpc = true, + .tx_stbc = true, .max_power_index = 0x3f, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_2, .amsdu_in_ampdu = false, /* RX speed is better without AMSDU */ -- 2.53.0 rtw_dynamic_csi_rate() runs from the watchdog for each vif that is a SU or MU beamformee. new_csi_rate_idx is only written by the cfg_csi_rate chip op, so on a chip without that op such as 88xxa, an uninitialized value is compared with cur_csi_rpt_rate. Return early when the chip has no cfg_csi_rate op. Suggested-by: Luka Gejak Signed-off-by: Ho Jie Feng --- drivers/net/wireless/realtek/rtw88/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index e243738809..a8a603aaee 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -174,6 +174,9 @@ static void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) u8 fix_rate_enable = 0; u8 new_csi_rate_idx; + if (!rtwdev->chip->ops->cfg_csi_rate) + return; + if (rtwvif->bfee.role != RTW_BFEE_SU && rtwvif->bfee.role != RTW_BFEE_MU) return; -- 2.53.0 Make MU and SU capability flags each depend on the chip declared maximum instead of setting both flags together. Signed-off-by: Ho Jie Feng --- drivers/net/wireless/realtek/rtw88/main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index a8a603aaee..b0c338954b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1606,6 +1606,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, static void rtw_init_vht_cap(struct rtw_dev *rtwdev, struct ieee80211_sta_vht_cap *vht_cap) { + const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_efuse *efuse = &rtwdev->efuse; u16 mcs_map = 0; __le16 highest; @@ -1624,10 +1625,13 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev, 0; if (rtwdev->hal.rf_path_num > 1) vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; - vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | - IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; - vht_cap->cap |= (rtwdev->hal.bfee_sts_cap << - IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + if (rtw_bf_support && chip->bfer_su_max_num) { + vht_cap->cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + vht_cap->cap |= rtwdev->hal.bfee_sts_cap << + IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; + } + if (rtw_bf_support && chip->bfer_mu_max_num) + vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; if (rtw_chip_has_rx_ldpc(rtwdev)) vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; -- 2.53.0 Implement beamformee support for 88xxa since they have support for it. Signed-off-by: Ho Jie Feng --- drivers/net/wireless/realtek/rtw88/bf.h | 7 ++ drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8812a.c | 3 +- drivers/net/wireless/realtek/rtw88/rtw8814a.c | 42 ++++++++++- drivers/net/wireless/realtek/rtw88/rtw8821a.c | 3 +- drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 73 +++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 2 + 7 files changed, 126 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/bf.h b/drivers/net/wireless/realtek/rtw88/bf.h index a5d3010e6b..3a53e69d01 100644 --- a/drivers/net/wireless/realtek/rtw88/bf.h +++ b/drivers/net/wireless/realtek/rtw88/bf.h @@ -12,9 +12,16 @@ #define REG_ASSOCIATED_BFMER0_INFO 0x06E4 #define REG_ASSOCIATED_BFMER1_INFO 0x06EC #define REG_TX_CSI_RPT_PARAM_BW20 0x06F4 +#define REG_TX_CSI_RPT_PARAM_BW40 0x06F8 +#define REG_TX_CSI_RPT_PARAM_BW80 0x06FC #define REG_SND_PTCL_CTRL 0x0718 +#define BIT_USE_NSTS BIT(7) #define BIT_DIS_CHK_VHTSIGB_CRC BIT(6) #define BIT_DIS_CHK_VHTSIGA_CRC BIT(5) +#define BIT_BFPARAM_SEL BIT(4) +#define BIT_CSISEQ_SEL BIT(3) +#define BIT_HT_NDPA_EN BIT(1) +#define BIT_VHT_NDPA_EN BIT(0) #define BIT_MASK_BEAMFORM (GENMASK(4, 0) | BIT(7)) #define REG_MU_TX_CTL 0x14C0 #define REG_MU_STA_GID_VLD 0x14C4 diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index afcdb66fdb..f8ec1e2931 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -671,6 +671,7 @@ #define REG_IQK_COM96 0x0984 #define REG_FAS 0x09a4 +#define REG_CSI_CONTENT_VALUE 0x09b4 #define REG_RXSB 0x0a00 #define BIT_RXSB_ANA_DIV BIT(15) #define REG_CCK_RX 0x0a04 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index 55f1d3d324..5d58dff4fc 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -931,7 +931,7 @@ static const struct rtw_chip_ops rtw8812a_ops = { .phy_calibration = rtw8812a_phy_calibration, .cck_pd_set = rtw_phy_cck_pd_set, .pwr_track = rtw8812a_pwr_track, - .config_bfee = NULL, + .config_bfee = rtw88xxa_bf_config_bfee, .set_gid_table = NULL, .cfg_csi_rate = NULL, .led_set = rtw8812a_led_set, @@ -1084,6 +1084,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = { .old_datarate_fb_limit = true, .usb_tx_agg_desc_num = 1, .iqk_threshold = 8, + .bfer_su_max_num = 2, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c index e35c57c9d1..13c22d2e50 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c @@ -4,6 +4,7 @@ #include #include "main.h" +#include "bf.h" #include "coex.h" #include "tx.h" #include "phy.h" @@ -115,10 +116,13 @@ static void rtw8814a_init_hwcap(struct rtw_dev *rtwdev) BIT(RTW_CHANNEL_WIDTH_80); efuse->hw_cap.ptcl = EFUSE_HW_CAP_PTCL_VHT; - if (hal->rf_type == RF_3T3R) + if (hal->rf_type == RF_3T3R) { efuse->hw_cap.nss = 3; - else + hal->bfee_sts_cap = 2; + } else { efuse->hw_cap.nss = 2; + hal->bfee_sts_cap = 1; + } rtw_dbg(rtwdev, RTW_DBG_EFUSE, "hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n", @@ -2039,6 +2043,37 @@ static void rtw8814a_led_set(struct led_classdev *led, rtw_write32(rtwdev, REG_GPIO_PIN_CTRL_2, led_gpio_cfg); } +#define RTW_NDP_RX_STANDBY_TIME_8814A 0x40 +#define RTW_SND_CTRL_SOUNDING_8814A (BIT_USE_NSTS | \ + BIT_DIS_CHK_VHTSIGB_CRC | \ + BIT_BFPARAM_SEL | BIT_CSISEQ_SEL | \ + BIT_HT_NDPA_EN | BIT_VHT_NDPA_EN) +#define RTW_CSI_RPT_OFFSET_VHT_8814A 2 +#define RTW_CSI_RPT_OFFSET_HT_8814A 2 + +static void rtw8814a_bf_enable_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee) +{ + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); + + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 1, RTW_CSI_RPT_OFFSET_VHT_8814A); + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 2, RTW_CSI_RPT_OFFSET_HT_8814A); + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING_8814A); + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, + RTW_NDP_RX_STANDBY_TIME_8814A); +} + +static void rtw8814a_bf_config_bfee(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw8814a_bf_enable_bfee_su(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_su(rtwdev, bfee); +} + static void rtw8814a_fill_txdesc_checksum(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, u8 *txdesc) @@ -2068,7 +2103,7 @@ static const struct rtw_chip_ops rtw8814a_ops = { .phy_calibration = rtw8814a_phy_calibration, .cck_pd_set = rtw8814a_phy_cck_pd_set, .pwr_track = rtw8814a_pwr_track, - .config_bfee = NULL, + .config_bfee = rtw8814a_bf_config_bfee, .set_gid_table = NULL, .cfg_csi_rate = NULL, .led_set = rtw8814a_led_set, @@ -2231,6 +2266,7 @@ const struct rtw_chip_info rtw8814a_hw_spec = { .rfe_defs = rtw8814a_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8814a_rfe_defs), .iqk_threshold = 8, + .bfer_su_max_num = 2, .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, .coex_para_ver = 0, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c index 6096d3b8e4..6d106ae70d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -877,7 +877,7 @@ static const struct rtw_chip_ops rtw8821a_ops = { .phy_calibration = rtw8821a_phy_calibration, .cck_pd_set = rtw_phy_cck_pd_set, .pwr_track = rtw8821a_pwr_track, - .config_bfee = NULL, + .config_bfee = rtw88xxa_bf_config_bfee, .set_gid_table = NULL, .cfg_csi_rate = NULL, .led_set = rtw8821a_led_set, @@ -1188,6 +1188,7 @@ const struct rtw_chip_info rtw8821a_hw_spec = { .old_datarate_fb_limit = true, .usb_tx_agg_desc_num = 6, .iqk_threshold = 8, + .bfer_su_max_num = 2, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c index 5ffa29d181..9780999a9b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c @@ -138,6 +138,7 @@ static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev) efuse->hw_cap.nss = 1; else efuse->hw_cap.nss = 2; + hal->bfee_sts_cap = 1; if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) goto print_hw_cap; @@ -197,6 +198,78 @@ static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev) efuse->hw_cap.ant_num, efuse->hw_cap.nss); } +#define RTW_NDP_RX_STANDBY_TIME_88XXA 0x50 +#define RTW_SND_CTRL_REMOVE_88XXA (BIT_USE_NSTS | \ + BIT_DIS_CHK_VHTSIGB_CRC | \ + BIT_CSISEQ_SEL) +#define RTW_SND_CTRL_SOUNDING_88XXA (RTW_SND_CTRL_REMOVE_88XXA | \ + BIT_HT_NDPA_EN | BIT_VHT_NDPA_EN) +/* REG_CSI_CONTENT_VALUE from the 8812a (2T2R) and 8821a (1T1R) bb tables */ +#define RTW_CSI_CONTENT_2T2R_88XXA 0x00000000 +#define RTW_CSI_CONTENT_1T1R_88XXA 0x01081008 + +void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + static const u32 csi_rpt_regs[] = { + REG_TX_CSI_RPT_PARAM_BW20, + REG_TX_CSI_RPT_PARAM_BW40, + REG_TX_CSI_RPT_PARAM_BW80, + }; + struct rtw_bf_info *bf_info = &rtwdev->bf_info; + u8 nc_index = rtwdev->efuse.hw_cap.nss - 1; + u8 nr_index = 1, grouping = 0, codebookinfo = 1, coefficientsize = 0; + u8 slot = bfee->su_reg_index; + u32 addr_bfer_info; + u32 csi_param; + int i; + + if (bfee->role != RTW_BFEE_SU || slot >= 2) + return; + + addr_bfer_info = slot ? REG_ASSOCIATED_BFMER1_INFO : + REG_ASSOCIATED_BFMER0_INFO; + + rtw_dbg(rtwdev, RTW_DBG_BF, "SU beamformee %s slot %u\n", + enable ? "enable" : "disable", slot); + + if (!enable) { + rtw_write32(rtwdev, addr_bfer_info, 0); + rtw_write16(rtwdev, addr_bfer_info + 4, 0); + + clear_bit(slot, bf_info->bfer_su_reg_maping); + bfee->su_reg_index = 0xff; + + if (!bf_info->bfer_su_cnt) + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, + RTW_SND_CTRL_REMOVE_88XXA); + return; + } + + if (rtwdev->efuse.hw_cap.nss == 2) + rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, + RTW_CSI_CONTENT_2T2R_88XXA); + else + rtw_write32(rtwdev, REG_CSI_CONTENT_VALUE, + RTW_CSI_CONTENT_1T1R_88XXA); + + csi_param = (coefficientsize << 10) | (codebookinfo << 8) | + (grouping << 6) | (nr_index << 3) | nc_index; + /* same parameters for both beamformer slots */ + csi_param |= csi_param << 16; + + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING_88XXA); + for (i = 0; i < ETH_ALEN; i++) + rtw_write8(rtwdev, addr_bfer_info + i, bfee->mac_addr[i]); + + for (i = 0; i < ARRAY_SIZE(csi_rpt_regs); i++) + rtw_write32(rtwdev, csi_rpt_regs[i], csi_param); + + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, + RTW_NDP_RX_STANDBY_TIME_88XXA); +} +EXPORT_SYMBOL(rtw88xxa_bf_config_bfee); + int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map, u8 *phy_map) { const struct rtw_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h index 6597ca0dfc..150e86ea74 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h @@ -170,5 +170,7 @@ bool rtw88xxa_iqk_finish(int average, int threshold, void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev, void (*do_lck)(struct rtw_dev *rtwdev), void (*do_iqk)(struct rtw_dev *rtwdev)); +void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable); #endif -- 2.53.0 Promote chip specific functions into the common core for cfo tracking. These become helpers which can be used by the other drivers. Signed-off-by: Ho Jie Feng --- drivers/net/wireless/realtek/rtw88/phy.c | 106 ++++++++++++++++++ drivers/net/wireless/realtek/rtw88/phy.h | 2 + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 100 +---------------- drivers/net/wireless/realtek/rtw88/rtw8822c.h | 3 - 4 files changed, 113 insertions(+), 98 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index e2515a662b..d0c1fb65be 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -720,6 +720,112 @@ void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev, } EXPORT_SYMBOL(rtw_phy_parsing_cfo); +#define CFO_TRK_ENABLE_TH 20 +#define CFO_TRK_STOP_TH 10 +#define CFO_TRK_ADJ_TH 10 + +static u8 rtw_phy_cfo_tracking_reset(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_cfo_track *cfo = &dm_info->cfo_track; + + cfo->is_adjust = true; + + if (cfo->crystal_cap > rtwdev->efuse.crystal_cap) + return cfo->crystal_cap - 1; + else if (cfo->crystal_cap < rtwdev->efuse.crystal_cap) + return cfo->crystal_cap + 1; + + return cfo->crystal_cap; +} + +void rtw_phy_cfo_xcap_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_cfo_track *cfo = &dm_info->cfo_track; + + cfo->crystal_cap = rtwdev->efuse.crystal_cap; + cfo->is_adjust = true; +} +EXPORT_SYMBOL(rtw_phy_cfo_xcap_init); + +#define REPORT_TO_KHZ(val) ({typeof(val) _v = (val); (_v << 1) + (_v >> 1); }) +static s32 rtw_phy_cfo_calc_avg(struct rtw_dev *rtwdev, u8 path_num) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_cfo_track *cfo = &dm_info->cfo_track; + s32 cfo_avg, cfo_path_sum = 0, cfo_rpt_sum; + u8 i; + + for (i = 0; i < path_num; i++) { + cfo_rpt_sum = REPORT_TO_KHZ(cfo->cfo_tail[i]); + + if (cfo->cfo_cnt[i]) + cfo_avg = cfo_rpt_sum / cfo->cfo_cnt[i]; + else + cfo_avg = 0; + + cfo_path_sum += cfo_avg; + } + + for (i = 0; i < path_num; i++) { + cfo->cfo_tail[i] = 0; + cfo->cfo_cnt[i] = 0; + } + + return cfo_path_sum / path_num; +} + +static void rtw_phy_cfo_need_adjust(struct rtw_dev *rtwdev, s32 cfo_avg) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_cfo_track *cfo = &dm_info->cfo_track; + + if (!cfo->is_adjust) { + if (abs(cfo_avg) > CFO_TRK_ENABLE_TH) + cfo->is_adjust = true; + } else { + if (abs(cfo_avg) <= CFO_TRK_STOP_TH) + cfo->is_adjust = false; + } +} + +u8 rtw_phy_cfo_xcap_track(struct rtw_dev *rtwdev, u8 xcap_max, bool bt_hold) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_cfo_track *cfo = &dm_info->cfo_track; + u8 path_num = rtwdev->hal.rf_path_num; + s8 crystal_cap = cfo->crystal_cap; + s32 cfo_avg = 0; + + if (rtwdev->sta_cnt != 1) + return rtw_phy_cfo_tracking_reset(rtwdev); + + if (cfo->packet_count == cfo->packet_count_pre) + return cfo->crystal_cap; + + cfo->packet_count_pre = cfo->packet_count; + cfo_avg = rtw_phy_cfo_calc_avg(rtwdev, path_num); + rtw_phy_cfo_need_adjust(rtwdev, cfo_avg); + + if (bt_hold) { + cfo->is_adjust = false; + return rtwdev->efuse.crystal_cap; + } + + if (cfo->is_adjust) { + if (cfo_avg > CFO_TRK_ADJ_TH) + crystal_cap++; + else if (cfo_avg < -CFO_TRK_ADJ_TH) + crystal_cap--; + + crystal_cap = clamp_t(s8, crystal_cap, 0, xcap_max); + } + + return (u8)crystal_cap; +} +EXPORT_SYMBOL(rtw_phy_cfo_xcap_track); + static void rtw_phy_cfo_track(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index 8a843aac73..b551cb860d 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -68,6 +68,8 @@ void rtw_phy_adaptivity_set_mode(struct rtw_dev *rtwdev); void rtw_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl); void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev, struct rtw_rx_pkt_stat *pkt_stat); +void rtw_phy_cfo_xcap_init(struct rtw_dev *rtwdev); +u8 rtw_phy_cfo_xcap_track(struct rtw_dev *rtwdev, u8 xcap_max, bool bt_hold); void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev); struct rtw_txpwr_lmt_cfg_pair { diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 09315d23e2..d7b0204e6d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -4243,103 +4243,13 @@ static void rtw8822c_set_crystal_cap(struct rtw_dev *rtwdev, u8 crystal_cap) rtw8822c_set_crystal_cap_reg(rtwdev, crystal_cap); } -static void rtw8822c_cfo_tracking_reset(struct rtw_dev *rtwdev) -{ - struct rtw_dm_info *dm_info = &rtwdev->dm_info; - struct rtw_cfo_track *cfo = &dm_info->cfo_track; - - cfo->is_adjust = true; - - if (cfo->crystal_cap > rtwdev->efuse.crystal_cap) - rtw8822c_set_crystal_cap(rtwdev, cfo->crystal_cap - 1); - else if (cfo->crystal_cap < rtwdev->efuse.crystal_cap) - rtw8822c_set_crystal_cap(rtwdev, cfo->crystal_cap + 1); -} - -static void rtw8822c_cfo_init(struct rtw_dev *rtwdev) -{ - struct rtw_dm_info *dm_info = &rtwdev->dm_info; - struct rtw_cfo_track *cfo = &dm_info->cfo_track; - - cfo->crystal_cap = rtwdev->efuse.crystal_cap; - cfo->is_adjust = true; -} - -#define REPORT_TO_KHZ(val) ({typeof(val) _v = (val); (_v << 1) + (_v >> 1); }) -static s32 rtw8822c_cfo_calc_avg(struct rtw_dev *rtwdev, u8 path_num) -{ - struct rtw_dm_info *dm_info = &rtwdev->dm_info; - struct rtw_cfo_track *cfo = &dm_info->cfo_track; - s32 cfo_avg, cfo_path_sum = 0, cfo_rpt_sum; - u8 i; - - for (i = 0; i < path_num; i++) { - cfo_rpt_sum = REPORT_TO_KHZ(cfo->cfo_tail[i]); - - if (cfo->cfo_cnt[i]) - cfo_avg = cfo_rpt_sum / cfo->cfo_cnt[i]; - else - cfo_avg = 0; - - cfo_path_sum += cfo_avg; - } - - for (i = 0; i < path_num; i++) { - cfo->cfo_tail[i] = 0; - cfo->cfo_cnt[i] = 0; - } - - return cfo_path_sum / path_num; -} - -static void rtw8822c_cfo_need_adjust(struct rtw_dev *rtwdev, s32 cfo_avg) -{ - struct rtw_dm_info *dm_info = &rtwdev->dm_info; - struct rtw_cfo_track *cfo = &dm_info->cfo_track; - - if (!cfo->is_adjust) { - if (abs(cfo_avg) > CFO_TRK_ENABLE_TH) - cfo->is_adjust = true; - } else { - if (abs(cfo_avg) <= CFO_TRK_STOP_TH) - cfo->is_adjust = false; - } - - if (!rtw_coex_disabled(rtwdev)) { - cfo->is_adjust = false; - rtw8822c_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap); - } -} - static void rtw8822c_cfo_track(struct rtw_dev *rtwdev) { - struct rtw_dm_info *dm_info = &rtwdev->dm_info; - struct rtw_cfo_track *cfo = &dm_info->cfo_track; - u8 path_num = rtwdev->hal.rf_path_num; - s8 crystal_cap = cfo->crystal_cap; - s32 cfo_avg = 0; - - if (rtwdev->sta_cnt != 1) { - rtw8822c_cfo_tracking_reset(rtwdev); - return; - } - - if (cfo->packet_count == cfo->packet_count_pre) - return; - - cfo->packet_count_pre = cfo->packet_count; - cfo_avg = rtw8822c_cfo_calc_avg(rtwdev, path_num); - rtw8822c_cfo_need_adjust(rtwdev, cfo_avg); - - if (cfo->is_adjust) { - if (cfo_avg > CFO_TRK_ADJ_TH) - crystal_cap++; - else if (cfo_avg < -CFO_TRK_ADJ_TH) - crystal_cap--; + u8 crystal_cap; - crystal_cap = clamp_t(s8, crystal_cap, 0, XCAP_MASK); - rtw8822c_set_crystal_cap(rtwdev, (u8)crystal_cap); - } + crystal_cap = rtw_phy_cfo_xcap_track(rtwdev, XCAP_MASK, + !rtw_coex_disabled(rtwdev)); + rtw8822c_set_crystal_cap(rtwdev, crystal_cap); } static const struct rtw_phy_cck_pd_reg @@ -4985,7 +4895,7 @@ static const struct rtw_chip_ops rtw8822c_ops = { .cfg_csi_rate = rtw_bf_cfg_csi_rate, .adaptivity_init = rtw8822c_adaptivity_init, .adaptivity = rtw8822c_adaptivity, - .cfo_init = rtw8822c_cfo_init, + .cfo_init = rtw_phy_cfo_xcap_init, .cfo_track = rtw8822c_cfo_track, .config_tx_path = rtw8822c_config_tx_path, .config_txrx_mode = rtw8822c_config_trx_mode, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h index fc62b67a15..c27e4c394a 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h @@ -181,9 +181,6 @@ const struct rtw_table name ## _tbl = { \ #define REG_ANAPARLDO_POW_MAC 0x0029 #define BIT_LDOE25_PON BIT(0) #define XCAP_MASK GENMASK(6, 0) -#define CFO_TRK_ENABLE_TH 20 -#define CFO_TRK_STOP_TH 10 -#define CFO_TRK_ADJ_TH 10 #define REG_TXDFIR0 0x808 #define REG_DFIRBW 0x810 -- 2.53.0 Use the newly promoted helpers to implement support for 88xxa Signed-off-by: Ho Jie Feng --- drivers/net/wireless/realtek/rtw88/phy.c | 5 +- drivers/net/wireless/realtek/rtw88/phy.h | 6 +++ drivers/net/wireless/realtek/rtw88/rtw8812a.c | 2 + drivers/net/wireless/realtek/rtw88/rtw8814a.c | 32 +++++++++++-- drivers/net/wireless/realtek/rtw88/rtw8821a.c | 2 + drivers/net/wireless/realtek/rtw88/rtw88xxa.c | 47 +++++++++++++++---- drivers/net/wireless/realtek/rtw88/rtw88xxa.h | 1 + 7 files changed, 81 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index d0c1fb65be..b01601d707 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -687,13 +687,14 @@ static void rtw_phy_parsing_cfo_iter(void *data, u8 *mac, struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat; struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_cfo_track *cfo = &dm_info->cfo_track; + u8 path_num = min_t(u8, rtwdev->hal.rf_path_num, RTW_CFO_PATH_NUM_MAX); u8 *bssid = iter_data->bssid; u8 i; if (!ether_addr_equal(vif->bss_conf.bssid, bssid)) return; - for (i = 0; i < rtwdev->hal.rf_path_num; i++) { + for (i = 0; i < path_num; i++) { cfo->cfo_tail[i] += pkt_stat->cfo_tail[i]; cfo->cfo_cnt[i]++; } @@ -794,7 +795,7 @@ u8 rtw_phy_cfo_xcap_track(struct rtw_dev *rtwdev, u8 xcap_max, bool bt_hold) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_cfo_track *cfo = &dm_info->cfo_track; - u8 path_num = rtwdev->hal.rf_path_num; + u8 path_num = min_t(u8, rtwdev->hal.rf_path_num, RTW_CFO_PATH_NUM_MAX); s8 crystal_cap = cfo->crystal_cap; s32 cfo_avg = 0; diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index b551cb860d..52e6546b52 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -204,4 +204,10 @@ enum rtw_phy_cck_pd_lv { #define RRSR_RATE_ORDER_MAX 0xfffff #define RRSR_RATE_ORDER_CCK_LEN 4 +/* crystal cap width of all chips except RTL8822C */ +#define RTW_XCAP_MASK GENMASK(5, 0) + +/* RTL8814A has 4 paths, but only paths A and B report CFO */ +#define RTW_CFO_PATH_NUM_MAX 2 + #endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index 5d58dff4fc..c8008cf43d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -943,6 +943,8 @@ static const struct rtw_chip_ops rtw8812a_ops = { .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type, .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power, .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain, + .cfo_init = rtw_phy_cfo_xcap_init, + .cfo_track = rtw88xxa_cfo_track, }; static const struct rtw_page_table page_table_8812a[] = { diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c index 13c22d2e50..74c548cb5c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c @@ -146,6 +146,9 @@ static int rtw8814a_read_efuse(struct rtw_dev *rtwdev, u8 *log_map, u8 *phy_map) efuse->rfe_option = map->rfe_option; efuse->rf_board_option = map->rf_board_option; efuse->crystal_cap = map->xtal_k; + if (efuse->crystal_cap == 0xff) + efuse->crystal_cap = 0x20; + efuse->crystal_cap &= RTW_XCAP_MASK; efuse->channel_plan = map->channel_plan; efuse->country_code[0] = map->country_code[0]; efuse->country_code[1] = map->country_code[1]; @@ -284,9 +287,15 @@ static void rtw8814a_config_cck_rx_antenna_init(struct rtw_dev *rtwdev) rtw_write32_mask(rtwdev, REG_CCKTX, BIT_CMB_CCA_2R, 1); } +static void rtw8814a_set_crystal_cap(struct rtw_dev *rtwdev, u8 crystal_cap) +{ + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x07ff8000, + crystal_cap | (crystal_cap << 6)); +} + static void rtw8814a_phy_set_param(struct rtw_dev *rtwdev) { - u32 crystal_cap, val32; + u32 val32; u8 val8, rf_path; /* power on BB/RF domain */ @@ -308,9 +317,7 @@ static void rtw8814a_phy_set_param(struct rtw_dev *rtwdev) rtw_load_table(rtwdev, rtwdev->chip->bb_tbl); rtw_load_table(rtwdev, rtwdev->chip->agc_tbl); - crystal_cap = rtwdev->efuse.crystal_cap & 0x3F; - crystal_cap |= crystal_cap << 6; - rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x07ff8000, crystal_cap); + rtw8814a_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap); rtw8814a_config_trx_path(rtwdev); @@ -1269,6 +1276,8 @@ static void rtw8814a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->cfo_tail[i] = cfo[i]; dm_info->cfo_tail[i] = (cfo[i] * 5) >> 1; } + + rtw_phy_parsing_cfo(rtwdev, pkt_stat); } } @@ -2074,6 +2083,19 @@ static void rtw8814a_bf_config_bfee(struct rtw_dev *rtwdev, rtw_bf_remove_bfee_su(rtwdev, bfee); } +static void rtw8814a_cfo_track(struct rtw_dev *rtwdev) +{ + struct rtw_cfo_track *cfo = &rtwdev->dm_info.cfo_track; + u8 crystal_cap; + + crystal_cap = rtw_phy_cfo_xcap_track(rtwdev, RTW_XCAP_MASK, false); + if (crystal_cap == cfo->crystal_cap) + return; + + cfo->crystal_cap = crystal_cap; + rtw8814a_set_crystal_cap(rtwdev, crystal_cap); +} + static void rtw8814a_fill_txdesc_checksum(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, u8 *txdesc) @@ -2108,6 +2130,8 @@ static const struct rtw_chip_ops rtw8814a_ops = { .cfg_csi_rate = NULL, .led_set = rtw8814a_led_set, .fill_txdesc_checksum = rtw8814a_fill_txdesc_checksum, + .cfo_init = rtw_phy_cfo_xcap_init, + .cfo_track = rtw8814a_cfo_track, .coex_set_init = rtw8814a_coex_cfg_init, .coex_set_ant_switch = rtw8814a_coex_cfg_ant_switch, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c index 6d106ae70d..17d3677ca4 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -889,6 +889,8 @@ static const struct rtw_chip_ops rtw8821a_ops = { .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type, .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power, .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain, + .cfo_init = rtw_phy_cfo_xcap_init, + .cfo_track = rtw88xxa_cfo_track, }; static const struct rtw_page_table page_table_8821a[] = { diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c index 9780999a9b..68a4ca8069 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c @@ -290,6 +290,7 @@ int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map, u8 *phy_map) efuse->crystal_cap = map->xtal_k; if (efuse->crystal_cap == 0xff) efuse->crystal_cap = 0x20; + efuse->crystal_cap &= RTW_XCAP_MASK; efuse->pa_type_2g = map->pa_type; efuse->pa_type_5g = map->pa_type; efuse->lna_type_2g = map->lna_type_2g; @@ -643,9 +644,19 @@ static void rtw88xxa_init_beacon_parameters(struct rtw_dev *rtwdev) rtw_write16(rtwdev, REG_BCNTCFG, 0x4413); } +static void rtw88xxa_set_crystal_cap(struct rtw_dev *rtwdev, u8 crystal_cap) +{ + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x7FF80000, + crystal_cap | (crystal_cap << 6)); + else + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x00FFF000, + crystal_cap | (crystal_cap << 6)); +} + static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev) { - u8 val8, crystal_cap; + u8 val8; /* power on BB/RF domain */ val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN); @@ -664,13 +675,7 @@ static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev) rtw_load_table(rtwdev, rtwdev->chip->bb_tbl); rtw_load_table(rtwdev, rtwdev->chip->agc_tbl); - crystal_cap = rtwdev->efuse.crystal_cap & 0x3F; - if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) - rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x7FF80000, - crystal_cap | (crystal_cap << 6)); - else - rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x00FFF000, - crystal_cap | (crystal_cap << 6)); + rtw88xxa_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap); } static void rtw88xxa_phy_rf_config(struct rtw_dev *rtwdev) @@ -1632,6 +1637,17 @@ void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, power_b = power_a; pkt_stat->signal_power = max3(power_a, power_b, min_rx_power); + + pkt_stat->cfo_tail[RF_PATH_A] = + (s8)le32_get_bits(rpt->w2, RTW_JGRPHY_W2_CFO_TAIL_A); + pkt_stat->cfo_tail[RF_PATH_B] = + (s8)le32_get_bits(rpt->w2, RTW_JGRPHY_W2_CFO_TAIL_B); + + /* convert to kHz (used only for debugfs) */ + for (i = RF_PATH_A; i < rtwdev->hal.rf_path_num; i++) + dm_info->cfo_tail[i] = (pkt_stat->cfo_tail[i] * 5) >> 1; + + rtw_phy_parsing_cfo(rtwdev, pkt_stat); } } EXPORT_SYMBOL(rtw88xxa_query_phy_status); @@ -2020,6 +2036,21 @@ void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev, } EXPORT_SYMBOL(rtw88xxa_phy_pwrtrack); +void rtw88xxa_cfo_track(struct rtw_dev *rtwdev) +{ + struct rtw_cfo_track *cfo = &rtwdev->dm_info.cfo_track; + bool bt_hold = rtwdev->efuse.btcoex && !rtw_coex_disabled(rtwdev); + u8 crystal_cap; + + crystal_cap = rtw_phy_cfo_xcap_track(rtwdev, RTW_XCAP_MASK, bt_hold); + if (crystal_cap == cfo->crystal_cap) + return; + + cfo->crystal_cap = crystal_cap; + rtw88xxa_set_crystal_cap(rtwdev, crystal_cap); +} +EXPORT_SYMBOL(rtw88xxa_cfo_track); + MODULE_AUTHOR("Realtek Corporation"); MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h index 150e86ea74..188b8f3a4b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h @@ -172,5 +172,6 @@ void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev, void (*do_iqk)(struct rtw_dev *rtwdev)); void rtw88xxa_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, struct rtw_bfee *bfee, bool enable); +void rtw88xxa_cfo_track(struct rtw_dev *rtwdev); #endif -- 2.53.0 Honor the peer-advertised receive limit for transmitted A-MPDUs. Signed-off-by: Ho Jie Feng --- drivers/net/wireless/realtek/rtw88/rtw8812a.c | 11 ++++++++++- drivers/net/wireless/realtek/rtw88/rtw8821a.c | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index c8008cf43d..7e3c86160f 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -78,6 +78,15 @@ static void rtw8812a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { } +static void rtw8812a_set_ampdu_factor(struct rtw_dev *rtwdev, u8 factor) +{ + factor = min_t(u8, factor, IEEE80211_VHT_MAX_AMPDU_128K); + + /* the vendor driver sets the undocumented BIT(31) */ + rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, + ((8192 << factor) - 1) | BIT(31)); +} + static void rtw8812a_do_lck(struct rtw_dev *rtwdev) { u32 cont_tx, lc_cal, i; @@ -926,7 +935,7 @@ static const struct rtw_chip_ops rtw8812a_ops = { .set_tx_power_index = rtw88xxa_set_tx_power_index, .cfg_ldo25 = rtw8812a_cfg_ldo25, .efuse_grant = rtw88xxa_efuse_grant, - .set_ampdu_factor = NULL, + .set_ampdu_factor = rtw8812a_set_ampdu_factor, .false_alarm_statistics = rtw88xxa_false_alarm_statistics, .phy_calibration = rtw8812a_phy_calibration, .cck_pd_set = rtw_phy_cck_pd_set, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c index 17d3677ca4..408b5ecdc5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -49,6 +49,15 @@ static void rtw8821a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { } +static void rtw8821a_set_ampdu_factor(struct rtw_dev *rtwdev, u8 factor) +{ + factor = min_t(u8, factor, IEEE80211_VHT_MAX_AMPDU_64K); + + /* the vendor driver sets the undocumented BIT(31) */ + rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, + ((8192 << factor) - 1) | BIT(31)); +} + #define CAL_NUM_8821A 3 #define MACBB_REG_NUM_8821A 8 #define AFE_REG_NUM_8821A 4 @@ -872,7 +881,7 @@ static const struct rtw_chip_ops rtw8821a_ops = { .set_tx_power_index = rtw88xxa_set_tx_power_index, .cfg_ldo25 = rtw8821a_cfg_ldo25, .efuse_grant = rtw88xxa_efuse_grant, - .set_ampdu_factor = NULL, + .set_ampdu_factor = rtw8821a_set_ampdu_factor, .false_alarm_statistics = rtw88xxa_false_alarm_statistics, .phy_calibration = rtw8821a_phy_calibration, .cck_pd_set = rtw_phy_cck_pd_set, -- 2.53.0