In 3-link hybrid MLO the firmware aggregates all links under the primary link OMAC. Derive the TX OM-remap index from the current valid_links when the BSS MLD TLV is built, set it there and in the TXD with OM_MAP (BIT(9) on MT7925 and MT7928, BIT(8) otherwise). Without hybrid MLO the TXD is unchanged. Signed-off-by: Emery Hsin --- drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 13 ++++++++++++- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 15 ++++++++++++++- drivers/net/wireless/mediatek/mt76/mt792x.h | 4 ++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 20acfcb9d1b9..6668a0c9a28d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -761,6 +761,7 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | BSS_CHANGED_FILS_DISCOVERY)); struct mt792x_bss_conf *mconf; + u32 om_map = 0; mconf = vif ? mt792x_vif_to_link((struct mt792x_vif *)vif->drv_priv, wcid->link_id) : NULL; @@ -772,6 +773,16 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, band_idx = mvif->band_idx; } + /* hybrid MLO: send every link under the primary OMAC via the OM remap + * table + */ + if (mconf && mconf->om_remap_idx != MT792x_OM_REMAP_IDX_NONE) { + omac_idx = mconf->om_remap_idx; + /* OM_MAP is BIT(9) on MT7925/MT7928, BIT(8) on other chips */ + om_map = is_mt7925(dev) || is_mt7928(dev) ? + MT_TXD2_OWN_MAC_MAP_V2 : MT_TXD2_OWN_MAC_MAP; + } + if (inband_disc) { p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_ALTX0; @@ -804,7 +815,7 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, val |= FIELD_PREP(MT_TXD1_TGID, band_idx); txwi[1] = cpu_to_le32(val); - txwi[2] = 0; + txwi[2] = cpu_to_le32(om_map); val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 2b1346044c5a..d272c06df254 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -403,6 +403,11 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev, mconf->mt76.omac_idx = mvif->bss_conf.mt76.idx; else mconf->mt76.omac_idx = mconf->mt76.idx; + /* The hybrid-MLO TX OM remap index is derived per BSS_INFO from the + * current valid_links in mt7925_mcu_bss_mld_tlv(), not here: the deflink + * is added before the MLD exists. + */ + mconf->om_remap_idx = MT792x_OM_REMAP_IDX_NONE; mconf->mt76.band_idx = MT792x_BAND_AUTO; mconf->absent = false; @@ -1538,6 +1543,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, /* reset to auto band so the deactivate drops the band binding */ mconf->mt76.band_idx = MT792x_BAND_AUTO; + mconf->om_remap_idx = MT792x_OM_REMAP_IDX_NONE; /* back to the legacy WMM index, MLO uses 0 */ mconf->mt76.wmm_idx = mconf->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; @@ -1608,6 +1614,7 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, /* reset to auto band before the disconnect command */ mconf->mt76.band_idx = MT792x_BAND_AUTO; + mconf->om_remap_idx = MT792x_OM_REMAP_IDX_NONE; mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf, link_sta, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 2c2ab85180c4..d02242870115 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -3272,10 +3272,14 @@ mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, struct bss_mld_tlv *mld; struct tlv *tlv; bool is_mld; + bool is_hybrid; bool is_supported_ap = false; is_mld = ieee80211_vif_is_mld(link_conf->vif) || (hweight16(mvif->valid_links) > 1); + /* three links means hybrid MLO */ + is_hybrid = hweight16(mvif->valid_links) >= 3 && + (phy->chip_cap & BIT(MT792x_CHIP_CAP_MLO_HYBRID_EN)); tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld)); mld = (struct bss_mld_tlv *)tlv; @@ -3284,7 +3288,16 @@ mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, /* apply the index of the primary link */ mld->group_mld_id = is_mld ? mvif->bss_conf.mt76.idx : 0xff; mld->own_mld_id = mconf->mt76.idx + 32; - mld->remap_idx = 0xff; + /* Hybrid MLO remaps every link's TX OWN_MAC to the primary link OMAC; + * derive it here from the current valid_links so the deflink (added + * before the MLD existed) is covered too, and cache it for the TX path. + */ + mld->remap_idx = is_hybrid ? mvif->bss_conf.mt76.omac_idx : + MT792x_OM_REMAP_IDX_NONE; + mconf->om_remap_idx = mld->remap_idx; + + /* enable hybrid MLO in firmware */ + mld->hybrid_mode = is_hybrid; /* single active link, STR is not supported */ mld->max_link_num = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index f1a0a296ae0f..7d5ef7d785a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -176,6 +176,9 @@ struct mt792x_chanctx { struct mt792x_bss_conf *bss_conf; }; +/* no OM remap */ +#define MT792x_OM_REMAP_IDX_NONE 0xff + struct mt792x_bss_conf { struct mt76_vif_link mt76; /* must be first */ struct mt792x_vif *vif; @@ -189,6 +192,7 @@ struct mt792x_bss_conf { /* For group-addressed frames that are sent outside a TXQ */ struct mt792x_link_sta bmc; bool bmc_valid; + u8 om_remap_idx; /* TX OM remap index, 0xff if none */ }; struct mt792x_nan_conf { -- 2.45.2