Commit e411b819 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

wifi: mt76: add multi-radio support to scanning code

When scanning on a phy/vif combination that does not have an active link,
create a temporary link in order to ensure that we have a valid wcid.

Link: https://patch.msgid.link/20250102163508.52945-11-nbd@nbd.name


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 716cc146
Loading
Loading
Loading
Loading
+61 −1
Original line number Diff line number Diff line
@@ -4,6 +4,20 @@
 */
#include "mt76.h"

static struct mt76_vif_link *
mt76_alloc_mlink(struct mt76_dev *dev, struct mt76_vif_data *mvif)
{
	struct mt76_vif_link *mlink;

	mlink = kzalloc(dev->drv->link_data_size, GFP_KERNEL);
	if (!mlink)
		return NULL;

	mlink->mvif = mvif;

	return mlink;
}

static int
mt76_phy_update_channel(struct mt76_phy *phy,
			struct ieee80211_chanctx_conf *conf)
@@ -108,7 +122,7 @@ int mt76_assign_vif_chanctx(struct ieee80211_hw *hw,

	mlink = mt76_vif_conf_link(dev, vif, link_conf);
	if (!mlink) {
		mlink = kzalloc(dev->drv->link_data_size, GFP_KERNEL);
		mlink = mt76_alloc_mlink(dev, mvif);
		if (!mlink) {
			ret = -ENOMEM;
			goto out;
@@ -248,3 +262,49 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
	return ret;
}
EXPORT_SYMBOL_GPL(mt76_switch_vif_chanctx);

struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
					    struct ieee80211_vif *vif)
{
	struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
	struct mt76_vif_data *mvif = mlink->mvif;
	struct mt76_dev *dev = phy->dev;
	int i, ret;

	for (i = 0; i < ARRAY_SIZE(mvif->link); i++) {
		mlink = mt76_dereference(mvif->link[i], dev);
		if (!mlink)
			continue;

		if (mt76_vif_link_phy(mlink) == phy)
			return mlink;
	}

	if (!dev->drv->vif_link_add)
		return ERR_PTR(-EINVAL);

	mlink = mt76_alloc_mlink(dev, mvif);
	if (!mlink)
		return ERR_PTR(-ENOMEM);

	mlink->offchannel = true;
	ret = dev->drv->vif_link_add(phy, vif, &vif->bss_conf, mlink);
	if (ret) {
		kfree(mlink);
		return ERR_PTR(ret);
	}

	return mlink;
}

void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
			   struct mt76_vif_link *mlink)
{
	struct mt76_dev *dev = phy->dev;

	if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel)
		return;

	dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
	kfree(mlink);
}
+6 −0
Original line number Diff line number Diff line
@@ -777,6 +777,7 @@ struct mt76_vif_link {
	u8 basic_rates_idx;
	u8 mcast_rates_idx;
	u8 beacon_rates_idx;
	bool offchannel;
	struct ieee80211_chanctx_conf *ctx;
	struct mt76_wcid *wcid;
	struct mt76_vif_data *mvif;
@@ -942,6 +943,7 @@ struct mt76_dev {
		struct cfg80211_scan_request *req;
		struct ieee80211_channel *chan;
		struct ieee80211_vif *vif;
		struct mt76_vif_link *mlink;
		struct mt76_phy *phy;
		int chan_idx;
	} scan;
@@ -1570,6 +1572,10 @@ int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
		     bool offchannel);
void mt76_scan_work(struct work_struct *work);
void mt76_abort_scan(struct mt76_dev *dev);
struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
					    struct ieee80211_vif *vif);
void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
			   struct mt76_vif_link *mlink);

/* usb */
static inline bool mt76u_urb_error(struct urb *urb)
+10 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort)

	if (dev->scan.chan && phy->main_chandef.chan)
		mt76_set_channel(phy, &phy->main_chandef, false);
	mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
	memset(&dev->scan, 0, sizeof(dev->scan));
	ieee80211_scan_completed(phy->hw, &info);
}
@@ -33,7 +34,7 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
{
	struct cfg80211_scan_request *req = dev->scan.req;
	struct ieee80211_vif *vif = dev->scan.vif;
	struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;
	struct mt76_vif_link *mvif = dev->scan.mlink;
	enum nl80211_band band = dev->scan.chan->band;
	struct mt76_phy *phy = dev->scan.phy;
	struct ieee80211_tx_info *info;
@@ -122,6 +123,7 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
	struct mt76_phy *phy = hw->priv;
	struct mt76_dev *dev = phy->dev;
	struct mt76_vif_link *mlink;
	int ret = 0;

	if (hw->wiphy->n_radio > 1) {
@@ -137,10 +139,17 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		goto out;
	}

	mlink = mt76_get_vif_phy_link(phy, vif);
	if (IS_ERR(mlink)) {
		ret = PTR_ERR(mlink);
		goto out;
	}

	memset(&dev->scan, 0, sizeof(dev->scan));
	dev->scan.req = &req->req;
	dev->scan.vif = vif;
	dev->scan.phy = phy;
	dev->scan.mlink = mlink;
	ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0);

out: