Commit f5160304 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau
Browse files

wifi: mt76: mt7996: Enable MLO support for client interfaces



Report MT7996 MLO STA capabilities to mac80211 stack.

Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250901-mt7996-enable-mlo-client-v1-1-50c46317325d@kernel.org


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 24e2846f
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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)
+1 −51
Original line number Diff line number Diff line
@@ -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)
+8 −0
Original line number Diff line number Diff line
@@ -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),
	},
};

+26 −6
Original line number Diff line number Diff line
@@ -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);
}