]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: add multi-radio support to scanning code
authorFelix Fietkau <nbd@nbd.name>
Thu, 2 Jan 2025 16:34:55 +0000 (17:34 +0100)
committerFelix Fietkau <nbd@nbd.name>
Tue, 14 Jan 2025 12:42:29 +0000 (13:42 +0100)
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: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/channel.c
drivers/net/wireless/mediatek/mt76/mt76.h
drivers/net/wireless/mediatek/mt76/scan.c

index 1cfeb09b0054c0290fad05f40861075e9f2d6ebe..ddb36e958c33cd099d25384dd2b5fb54442b4079 100644 (file)
@@ -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 @@ out:
        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);
+}
index 85b2f21acd703859ed93329eae52d82c7de92ba5..b61f1eb138e8b15be572a01ccc35c2887ee6f175 100644 (file)
@@ -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)
index d186a68b0fb80b4884d010ab8d041c42bbd99860..9f3485be57479fb9cd23ccc53d60dd3fafa89892 100644 (file)
@@ -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: