Commit 69acd6d9 authored by Sean Wang's avatar Sean Wang Committed by Felix Fietkau
Browse files

wifi: mt76: mt7925: add mt7925_change_vif_links



Add mt7925_change_vif_links to change the valid links on an interface,
supporting the MLO-enabled firmware.

Co-developed-by: default avatarMing Yen Hsieh <mingyen.hsieh@mediatek.com>
Signed-off-by: default avatarMing Yen Hsieh <mingyen.hsieh@mediatek.com>
Co-developed-by: default avatarDeren Wu <deren.wu@mediatek.com>
Signed-off-by: default avatarDeren Wu <deren.wu@mediatek.com>
Signed-off-by: default avatarSean Wang <sean.wang@mediatek.com>
Link: https://patch.msgid.link/31c9de30c3a18592c8e100f909845383b66f8677.1720248331.git.sean.wang@kernel.org


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 49681949
Loading
Loading
Loading
Loading
+130 −0
Original line number Diff line number Diff line
@@ -472,6 +472,33 @@ static int mt7925_set_roc(struct mt792x_phy *phy,
	return err;
}

static int mt7925_set_mlo_roc(struct mt792x_phy *phy,
			      struct mt792x_bss_conf *mconf,
			      u16 sel_links)
{
	int err;

	if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)))
		return -EBUSY;

	phy->roc_grant = false;

	err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id);
	if (err < 0) {
		clear_bit(MT76_STATE_ROC, &phy->mt76->state);
		goto out;
	}

	if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) {
		mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id);
		clear_bit(MT76_STATE_ROC, &phy->mt76->state);
		err = -ETIMEDOUT;
	}

out:
	return err;
}

static int mt7925_remain_on_channel(struct ieee80211_hw *hw,
				    struct ieee80211_vif *vif,
				    struct ieee80211_channel *chan,
@@ -1521,6 +1548,108 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw,
	mt792x_mutex_release(dev);
}

static int
mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			u16 old_links, u16 new_links,
			struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
{
	struct mt792x_bss_conf *mconfs[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *mconf;
	struct mt792x_link_sta *mlinks[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *mlink;
	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
	unsigned long add = new_links & ~old_links;
	unsigned long rem = old_links & ~new_links;
	struct mt792x_dev *dev = mt792x_hw_dev(hw);
	struct mt792x_phy *phy = mt792x_hw_phy(hw);
	struct ieee80211_bss_conf *link_conf;
	unsigned int link_id;
	int err;

	if (old_links == new_links)
		return 0;

	mt792x_mutex_acquire(dev);

	for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
		mconf = mt792x_vif_to_link(mvif, link_id);
		mlink = mt792x_sta_to_link(&mvif->sta, link_id);

		if (!mconf || !mlink)
			continue;

		if (mconf != &mvif->bss_conf) {
			mt792x_mac_link_bss_remove(dev, mconf, mlink);
			devm_kfree(dev->mt76.dev, mconf);
			devm_kfree(dev->mt76.dev, mlink);
		}

		rcu_assign_pointer(mvif->link_conf[link_id], NULL);
		rcu_assign_pointer(mvif->sta.link[link_id], NULL);
	}

	for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
		if (!old_links) {
			mconf = &mvif->bss_conf;
			mlink = &mvif->sta.deflink;
		} else {
			mconf = devm_kzalloc(dev->mt76.dev, sizeof(*mconf),
					     GFP_KERNEL);
			mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink),
					     GFP_KERNEL);
		}

		mconfs[link_id] = mconf;
		mlinks[link_id] = mlink;
		mconf->link_id = link_id;
		mconf->vif = mvif;
		mlink->wcid.link_id = link_id;
	}

	if (hweight16(mvif->valid_links) == 0)
		mt792x_mac_link_bss_remove(dev, &mvif->bss_conf,
					   &mvif->sta.deflink);

	for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
		mconf = mconfs[link_id];
		mlink = mlinks[link_id];
		link_conf = mt792x_vif_to_bss_conf(vif, link_id);

		rcu_assign_pointer(mvif->link_conf[link_id], mconf);
		rcu_assign_pointer(mvif->sta.link[link_id], mlink);

		err = mt7925_mac_link_bss_add(dev, link_conf, mlink);
		if (err < 0)
			goto free;

		if (mconf != &mvif->bss_conf) {
			err = mt7925_set_mlo_roc(phy, &mvif->bss_conf,
						 vif->active_links);
			if (err < 0)
				goto free;
		}
	}

	mvif->valid_links = new_links;

	mt792x_mutex_release(dev);

	return 0;

free:
	for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
		rcu_assign_pointer(mvif->link_conf[link_id], NULL);
		rcu_assign_pointer(mvif->sta.link[link_id], NULL);

		if (mconf != &mvif->bss_conf)
			devm_kfree(dev->mt76.dev, mconfs[link_id]);
		if (mlink != &mvif->sta.deflink)
			devm_kfree(dev->mt76.dev, mlinks[link_id]);
	}

	mt792x_mutex_release(dev);

	return err;
}

const struct ieee80211_ops mt7925_ops = {
	.tx = mt792x_tx,
	.start = mt7925_start,
@@ -1579,6 +1708,7 @@ const struct ieee80211_ops mt7925_ops = {
	.mgd_complete_tx = mt7925_mgd_complete_tx,
	.vif_cfg_changed = mt7925_vif_cfg_changed,
	.link_info_changed = mt7925_link_info_changed,
	.change_vif_links = mt7925_change_vif_links,
};
EXPORT_SYMBOL_GPL(mt7925_ops);

+98 −19
Original line number Diff line number Diff line
@@ -307,6 +307,9 @@ mt7925_mcu_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
	struct mt7925_roc_grant_tlv *grant = priv;

	if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION)
		return;

	if (mvif->idx != grant->bss_idx)
		return;

@@ -1084,6 +1087,100 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
	return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
}

int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
			   int duration, u8 token_id)
{
	struct mt792x_vif *mvif = mconf->vif;
	struct ieee80211_vif *vif = container_of((void *)mvif,
						 struct ieee80211_vif, drv_priv);
	struct ieee80211_bss_conf *link_conf;
	struct ieee80211_channel *chan;
	const u8 ch_band[] = {
		[NL80211_BAND_2GHZ] = 1,
		[NL80211_BAND_5GHZ] = 2,
		[NL80211_BAND_6GHZ] = 3,
	};
	enum mt7925_roc_req type;
	int center_ch, i = 0;
	bool is_AG_band = false;
	struct {
		u8 id;
		u8 bss_idx;
		u16 tag;
		struct mt792x_bss_conf *mconf;
		struct ieee80211_channel *chan;
	} links[2];

	struct {
		struct {
			u8 rsv[4];
		} __packed hdr;
		struct roc_acquire_tlv roc[2];
	} __packed req;

	if (!mconf || hweight16(vif->valid_links) < 2 ||
	    hweight16(sel_links) != 2)
		return -EPERM;

	for (i = 0; i < ARRAY_SIZE(links); i++) {
		links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) :
				 mconf->link_id;
		link_conf = mt792x_vif_to_bss_conf(vif, links[i].id);
		if (WARN_ON_ONCE(!link_conf))
			return -EPERM;

		links[i].chan = link_conf->chanreq.oper.chan;
		if (WARN_ON_ONCE(!links[i].chan))
			return -EPERM;

		links[i].mconf = mt792x_vif_to_link(mvif, links[i].id);
		links[i].tag = links[i].id == mconf->link_id ?
			       UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK;

		is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ;
	}

	if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)
		type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG :
				    MT7925_ROC_REQ_MLSR_AA;
	else
		type = MT7925_ROC_REQ_JOIN;

	for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) {
		if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan))
			continue;

		chan = links[i].chan;
		center_ch = ieee80211_frequency_to_channel(chan->center_freq);
		req.roc[i].len = cpu_to_le16(sizeof(struct roc_acquire_tlv));
		req.roc[i].tag = cpu_to_le16(links[i].tag);
		req.roc[i].tokenid = token_id;
		req.roc[i].reqtype = type;
		req.roc[i].maxinterval = cpu_to_le32(duration);
		req.roc[i].bss_idx = links[i].mconf->mt76.idx;
		req.roc[i].control_channel = chan->hw_value;
		req.roc[i].bw = CMD_CBW_20MHZ;
		req.roc[i].bw_from_ap = CMD_CBW_20MHZ;
		req.roc[i].center_chan = center_ch;
		req.roc[i].center_chan_from_ap = center_ch;

		/* STR : 0xfe indicates BAND_ALL with enabling DBDC
		 * EMLSR : 0xff indicates (BAND_AUTO) without DBDC
		 */
		req.roc[i].dbdcband = type == MT7925_ROC_REQ_JOIN ? 0xfe : 0xff;

		if (chan->hw_value < center_ch)
			req.roc[i].sco = 1; /* SCA */
		else if (chan->hw_value > center_ch)
			req.roc[i].sco = 3; /* SCB */

		req.roc[i].band = ch_band[chan->band];
	}

	return mt76_mcu_send_msg(&mvif->phy->dev->mt76, MCU_UNI_CMD(ROC),
				 &req, sizeof(req), false);
}

int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
		       struct ieee80211_channel *chan, int duration,
		       enum mt7925_roc_req type, u8 token_id)
@@ -1094,25 +1191,7 @@ int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
		struct {
			u8 rsv[4];
		} __packed hdr;
		struct roc_acquire_tlv {
			__le16 tag;
			__le16 len;
			u8 bss_idx;
			u8 tokenid;
			u8 control_channel;
			u8 sco;
			u8 band;
			u8 bw;
			u8 center_chan;
			u8 center_chan2;
			u8 bw_from_ap;
			u8 center_chan_from_ap;
			u8 center_chan2_from_ap;
			u8 reqtype;
			__le32 maxinterval;
			u8 dbdcband;
			u8 rsv[3];
		} __packed roc;
		struct roc_acquire_tlv roc;
	} __packed req = {
		.roc = {
			.tag = cpu_to_le16(UNI_ROC_ACQUIRE),
+20 −0
Original line number Diff line number Diff line
@@ -554,6 +554,26 @@ struct mt7925_wow_pattern_tlv {
	u8 rsv[7];
} __packed;

struct roc_acquire_tlv {
	__le16 tag;
	__le16 len;
	u8 bss_idx;
	u8 tokenid;
	u8 control_channel;
	u8 sco;
	u8 band;
	u8 bw;
	u8 center_chan;
	u8 center_chan2;
	u8 bw_from_ap;
	u8 center_chan_from_ap;
	u8 center_chan2_from_ap;
	u8 reqtype;
	__le32 maxinterval;
	u8 dbdcband;
	u8 rsv[3];
} __packed;

static inline enum connac3_mcu_cipher_type
mt7925_mcu_get_cipher(int cipher)
{
+6 −0
Original line number Diff line number Diff line
@@ -30,12 +30,16 @@
enum {
	UNI_ROC_ACQUIRE,
	UNI_ROC_ABORT,
	UNI_ROC_SUB_LINK = 3,
	UNI_ROC_NUM
};

enum mt7925_roc_req {
	MT7925_ROC_REQ_JOIN,
	MT7925_ROC_REQ_ROC,
	MT7925_ROC_REQ_SUB_LINK,
	MT7925_ROC_REQ_MLSR_AG = 10,
	MT7925_ROC_REQ_MLSR_AA,
	MT7925_ROC_REQ_NUM
};

@@ -295,6 +299,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw,
int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set);
int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
		       enum environment_cap env_cap);
int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
			   int duration, u8 token_id);
int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf,
		       struct ieee80211_channel *chan, int duration,
		       enum mt7925_roc_req type, u8 token_id);
+5 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ struct mt792x_bss_conf {
	struct mt792x_vif *vif;
	struct ewma_rssi rssi;
	struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
	unsigned int link_id;
};

struct mt792x_vif {
@@ -122,6 +123,7 @@ struct mt792x_vif {
	struct mt792x_sta *wep_sta;

	struct mt792x_phy *phy;
	u16 valid_links;
};

struct mt792x_phy {
@@ -398,6 +400,9 @@ mt792x_get_mac80211_ops(struct device *dev,
int mt792x_init_wcid(struct mt792x_dev *dev);
int mt792x_mcu_drv_pmctrl(struct mt792x_dev *dev);
int mt792x_mcu_fw_pmctrl(struct mt792x_dev *dev);
void mt792x_mac_link_bss_remove(struct mt792x_dev *dev,
				struct mt792x_bss_conf *mconf,
				struct mt792x_link_sta *mlink);

static inline char *mt792x_ram_name(struct mt792x_dev *dev)
{
Loading