diff options
| author | Lorenzo Bianconi <lorenzo@kernel.org> | 2025-09-01 15:02:33 +0200 |
|---|---|---|
| committer | Felix Fietkau <nbd@nbd.name> | 2025-09-15 09:47:40 +0200 |
| commit | f5160304d57c5543c63404a15cc8737ef714b669 (patch) | |
| tree | ba9b45f661f6cef22c48b7043a8bf05e5be17d3a | |
| parent | 24e2846f15b045f323692adcf24cabfcba7f7de6 (diff) | |
wifi: mt76: mt7996: Enable MLO support for client interfaces
Report MT7996 MLO STA capabilities to mac80211 stack.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250901-mt7996-enable-mlo-client-v1-1-50c46317325d@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mac80211.c | 52 | ||||
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt76.h | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7925/main.c | 52 | ||||
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7996/init.c | 8 | ||||
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7996/main.c | 32 |
5 files changed, 88 insertions, 57 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 59adf3312617..6ef186107782 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -2060,3 +2060,55 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif) mt76_abort_roc(mvif->roc_phy); } EXPORT_SYMBOL_GPL(mt76_vif_cleanup); + +u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links) +{ + unsigned long usable_links = ieee80211_vif_usable_links(vif); + struct { + u8 link_id; + enum nl80211_band band; + } data[IEEE80211_MLD_MAX_NUM_LINKS]; + unsigned int link_id; + int i, n_data = 0; + u16 sel_links = 0; + + if (!ieee80211_vif_is_mld(vif)) + return 0; + + if (vif->active_links == usable_links) + return vif->active_links; + + rcu_read_lock(); + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf; + + link_conf = rcu_dereference(vif->link_conf[link_id]); + if (WARN_ON_ONCE(!link_conf)) + continue; + + data[n_data].link_id = link_id; + data[n_data].band = link_conf->chanreq.oper.chan->band; + n_data++; + } + rcu_read_unlock(); + + for (i = 0; i < n_data; i++) { + int j; + + if (!(BIT(data[i].link_id) & vif->active_links)) + continue; + + sel_links = BIT(data[i].link_id); + for (j = 0; j < n_data; j++) { + if (data[i].band != data[j].band) { + sel_links |= BIT(data[j].link_id); + if (hweight16(sel_links) == max_active_links) + break; + } + } + break; + } + + return sel_links; +} +EXPORT_SYMBOL_GPL(mt76_select_links); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 127637454c82..5310b2a34edb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1872,6 +1872,7 @@ mt76_vif_init(struct ieee80211_vif *vif, struct mt76_vif_data *mvif) } void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif); +u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links); static inline struct mt76_vif_link * mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index c7903972b1d5..7416098db9fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -988,56 +988,6 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt7925_mac_sta_add); -static u16 -mt7925_mac_select_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) -{ - unsigned long usable_links = ieee80211_vif_usable_links(vif); - struct { - u8 link_id; - enum nl80211_band band; - } data[IEEE80211_MLD_MAX_NUM_LINKS]; - u8 link_id, i, j, n_data = 0; - u16 sel_links = 0; - - if (!ieee80211_vif_is_mld(vif)) - return 0; - - if (vif->active_links == usable_links) - return vif->active_links; - - rcu_read_lock(); - for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_bss_conf *link_conf = - rcu_dereference(vif->link_conf[link_id]); - - if (WARN_ON_ONCE(!link_conf)) - continue; - - data[n_data].link_id = link_id; - data[n_data].band = link_conf->chanreq.oper.chan->band; - n_data++; - } - rcu_read_unlock(); - - for (i = 0; i < n_data; i++) { - if (!(BIT(data[i].link_id) & vif->active_links)) - continue; - - sel_links = BIT(data[i].link_id); - - for (j = 0; j < n_data; j++) { - if (data[i].band != data[j].band) { - sel_links |= BIT(data[j].link_id); - break; - } - } - - break; - } - - return sel_links; -} - static void mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) { @@ -1048,7 +998,7 @@ mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; enum nl80211_band band = chandef->chan->band, secondary_band; - u16 sel_links = mt7925_mac_select_links(mdev, vif); + u16 sel_links = mt76_select_links(vif, 2); u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index a1fce8349dd4..21ac618d1c83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -79,6 +79,14 @@ static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { .mld_capa_and_ops = FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, MT7996_MAX_RADIOS - 1), + }, { + .iftype = NL80211_IFTYPE_STATION, + .extended_capabilities = if_types_ext_capa_ap, + .extended_capabilities_mask = if_types_ext_capa_ap, + .extended_capabilities_len = sizeof(if_types_ext_capa_ap), + .mld_capa_and_ops = + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, + MT7996_MAX_RADIOS - 1), }, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index c0144c7af94f..0d5866ac951f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1220,6 +1220,24 @@ mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, mutex_unlock(&dev->mt76.mutex); } +static void +mt7996_set_active_links(struct ieee80211_vif *vif) +{ + u16 active_links; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (!ieee80211_vif_is_mld(vif)) + return; + + active_links = mt76_select_links(vif, MT7996_MAX_RADIOS); + if (hweight16(active_links) < 2) + return; + + ieee80211_set_active_links_async(vif, active_links); +} + static int mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, @@ -1237,16 +1255,18 @@ mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt7996_mac_sta_remove(dev, vif, sta); if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_ASSOC) + new_state == IEEE80211_STA_ASSOC) { + mt7996_set_active_links(vif); ev = MT76_STA_EVENT_ASSOC; - else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTHORIZED) + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) { ev = MT76_STA_EVENT_AUTHORIZE; - else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTH) + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { ev = MT76_STA_EVENT_DISASSOC; - else + } else { return 0; + } return mt7996_mac_sta_event(dev, vif, sta, ev); } |