wifi: mt76: mt7996: add implicit beamforming support for mt7992

The configuration of mt7992 iBF has some differences to mt7996, rework
related code to make it work.
Also, most of our chipsets support iBF only on HT and VHT mode, except
mt7992 variant that has 5T on 5GHz band also supports iBF on HE and EHT
mode.

Co-developed-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
Link: https://patch.msgid.link/20250114101026.3587702-9-shayne.chen@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Howard Hsu
2025-01-14 18:10:26 +08:00
committed by Felix Fietkau
parent 57ccb37a90
commit ad4c9a8a98
2 changed files with 55 additions and 28 deletions

View File

@@ -1460,17 +1460,21 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
}
static void
mt7996_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
mt7996_mcu_sta_sounding_rate(struct sta_rec_bf *bf, struct mt7996_phy *phy)
{
bf->sounding_phy = MT_PHY_TYPE_OFDM;
bf->ndp_rate = 0; /* mcs0 */
bf->ndpa_rate = MT7996_CFEND_RATE_DEFAULT; /* ofdm 24m */
if (is_mt7996(phy->mt76->dev))
bf->ndpa_rate = MT7996_CFEND_RATE_DEFAULT; /* ofdm 24m */
else
bf->ndpa_rate = MT7992_CFEND_RATE_DEFAULT; /* ofdm 6m */
bf->rept_poll_rate = MT7996_CFEND_RATE_DEFAULT; /* ofdm 24m */
}
static void
mt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
struct sta_rec_bf *bf)
struct sta_rec_bf *bf, bool explicit)
{
struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs;
u8 n = 0;
@@ -1490,7 +1494,8 @@ mt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
bf->nrow = hweight8(phy->mt76->antenna_mask) - 1;
bf->ncol = min_t(u8, bf->nrow, n);
bf->ibf_ncol = n;
bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) :
min_t(u8, MT7996_IBF_MAX_NC, n);
}
static void
@@ -1508,7 +1513,7 @@ mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
if (explicit) {
u8 sts, snd_dim;
mt7996_mcu_sta_sounding_rate(bf);
mt7996_mcu_sta_sounding_rate(bf, phy);
sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
pc->cap);
@@ -1516,14 +1521,14 @@ mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
vc->cap);
bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant);
bf->ncol = min_t(u8, nss_mcs, bf->nrow);
bf->ibf_ncol = bf->ncol;
bf->ibf_ncol = min_t(u8, MT7996_IBF_MAX_NC, bf->ncol);
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
bf->nrow = 1;
} else {
bf->nrow = tx_ant;
bf->ncol = min_t(u8, nss_mcs, bf->nrow);
bf->ibf_ncol = nss_mcs;
bf->ibf_ncol = min_t(u8, MT7996_IBF_MAX_NC, nss_mcs);
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
bf->ibf_nrow = 1;
@@ -1532,7 +1537,8 @@ mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
static void
mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
struct mt7996_phy *phy, struct sta_rec_bf *bf)
struct mt7996_phy *phy, struct sta_rec_bf *bf,
bool explicit)
{
struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
@@ -1548,7 +1554,7 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
bf->tx_mode = MT_PHY_TYPE_HE_SU;
mt7996_mcu_sta_sounding_rate(bf);
mt7996_mcu_sta_sounding_rate(bf, phy);
bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
pe->phy_cap_info[6]);
@@ -1560,7 +1566,8 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
pe->phy_cap_info[4]);
bf->nrow = min_t(u8, snd_dim, sts);
bf->ncol = min_t(u8, nss_mcs, bf->nrow);
bf->ibf_ncol = bf->ncol;
bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) :
min_t(u8, MT7996_IBF_MAX_NC, nss_mcs);
if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160)
return;
@@ -1595,7 +1602,8 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
static void
mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
struct mt7996_phy *phy, struct sta_rec_bf *bf)
struct mt7996_phy *phy, struct sta_rec_bf *bf,
bool explicit)
{
struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
@@ -1609,7 +1617,7 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
bf->tx_mode = MT_PHY_TYPE_EHT_MU;
mt7996_mcu_sta_sounding_rate(bf);
mt7996_mcu_sta_sounding_rate(bf, phy);
bf->trigger_su = EHT_PHY(CAP3_TRIG_SU_BF_FDBK, pe->phy_cap_info[3]);
bf->trigger_mu = EHT_PHY(CAP3_TRIG_MU_BF_PART_BW_FDBK, pe->phy_cap_info[3]);
@@ -1618,7 +1626,8 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
(EHT_PHY(CAP1_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[1]) << 1);
bf->nrow = min_t(u8, snd_dim, sts);
bf->ncol = min_t(u8, nss_mcs, bf->nrow);
bf->ibf_ncol = bf->ncol;
bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) :
min_t(u8, MT7996_IBF_MAX_NC, nss_mcs);
if (sta->deflink.bandwidth < IEEE80211_STA_RX_BW_160)
return;
@@ -1653,12 +1662,15 @@ static void
mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{
#define EBF_MODE BIT(0)
#define IBF_MODE BIT(1)
#define BF_MAT_ORDER 4
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_phy *phy = mvif->deflink.phy;
int tx_ant = hweight16(phy->mt76->chainmask) - 1;
struct sta_rec_bf *bf;
struct tlv *tlv;
static const u8 matrix[4][4] = {
static const u8 matrix[BF_MAT_ORDER][BF_MAT_ORDER] = {
{0, 0, 0, 0},
{1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */
{2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */
@@ -1676,35 +1688,44 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
bf = (struct sta_rec_bf *)tlv;
/* he/eht: eBF only, in accordance with spec
/* he/eht: eBF only, except mt7992 that has 5T on 5GHz also supports iBF
* vht: support eBF and iBF
* ht: iBF only, since mac80211 lacks of eBF support
*/
if (sta->deflink.eht_cap.has_eht && ebf)
mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf);
else if (sta->deflink.he_cap.has_he && ebf)
mt7996_mcu_sta_bfer_he(sta, vif, phy, bf);
if (sta->deflink.eht_cap.has_eht)
mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf, ebf);
else if (sta->deflink.he_cap.has_he)
mt7996_mcu_sta_bfer_he(sta, vif, phy, bf, ebf);
else if (sta->deflink.vht_cap.vht_supported)
mt7996_mcu_sta_bfer_vht(sta, phy, bf, ebf);
else if (sta->deflink.ht_cap.ht_supported)
mt7996_mcu_sta_bfer_ht(sta, phy, bf);
mt7996_mcu_sta_bfer_ht(sta, phy, bf, ebf);
else
return;
bf->bf_cap = ebf ? ebf : dev->ibf << 1;
bf->bf_cap = ebf ? EBF_MODE : (dev->ibf ? IBF_MODE : 0);
if (is_mt7992(&dev->mt76) && tx_ant == 4)
bf->bf_cap |= IBF_MODE;
bf->bw = sta->deflink.bandwidth;
bf->ibf_dbw = sta->deflink.bandwidth;
bf->ibf_nrow = tx_ant;
if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
bf->ibf_timeout = 0x48;
if (sta->deflink.eht_cap.has_eht || sta->deflink.he_cap.has_he)
bf->ibf_timeout = is_mt7996(&dev->mt76) ? MT7996_IBF_TIMEOUT :
MT7992_IBF_TIMEOUT;
else if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
bf->ibf_timeout = MT7996_IBF_TIMEOUT_LEGACY;
else
bf->ibf_timeout = 0x18;
bf->ibf_timeout = MT7996_IBF_TIMEOUT;
if (ebf && bf->nrow != tx_ant)
bf->mem_20m = matrix[tx_ant][bf->ncol];
else
bf->mem_20m = matrix[bf->nrow][bf->ncol];
if (bf->ncol < BF_MAT_ORDER) {
if (ebf)
bf->mem_20m = tx_ant < BF_MAT_ORDER ?
matrix[tx_ant][bf->ncol] : 0;
else
bf->mem_20m = bf->nrow < BF_MAT_ORDER ?
matrix[bf->nrow][bf->ncol] : 0;
}
switch (sta->deflink.bandwidth) {
case IEEE80211_STA_RX_BW_160:

View File

@@ -68,6 +68,12 @@
#define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
#define MT7996_IBF_MAX_NC 2
#define MT7996_IBF_TIMEOUT 0x18
#define MT7996_IBF_TIMEOUT_LEGACY 0x48
#define MT7992_CFEND_RATE_DEFAULT 0x4b /* OFDM 6M */
#define MT7992_IBF_TIMEOUT 0xff
#define MT7996_SKU_RATE_NUM 417
#define MT7996_SKU_PATH_NUM 494