]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
wifi: mt76: mt7921: introduce chanctx support
authorSean Wang <sean.wang@mediatek.com>
Tue, 15 Nov 2022 00:11:24 +0000 (08:11 +0800)
committerFelix Fietkau <nbd@nbd.name>
Thu, 1 Dec 2022 16:29:13 +0000 (17:29 +0100)
The firmware can have the capability to manage the channel context
scheduling on multiple roles running on the device including Station,
AP and P2P GC/GO mode (will be extended based on the future patchset)
to help users sharing the network with others on a single device.

The firmware is able to support the channel chanctx up to 2 interface
simultaneously running on the different channels.

Another thing to be noted is that before the driver is going sent out the
management frames, the driver has to get the privilege from the firmware
to occupy the current channel context until the frame handshake is
completed and then get the privilege back to the firmware.

Co-developed-by: Deren Wu <deren.wu@mediatek.com>
Signed-off-by: Deren Wu <deren.wu@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7921/init.c
drivers/net/wireless/mediatek/mt76/mt7921/mac.c
drivers/net/wireless/mediatek/mt76/mt7921/main.c
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
drivers/net/wireless/mediatek/mt76/mt7921/pci.c
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
drivers/net/wireless/mediatek/mt76/mt7921/usb.c

index e9353e9929a9d09691043e4c8c97543c1ebb1d27..79b8055ce4c4f55ccd08e9f1c15064bddfd33234 100644 (file)
@@ -26,6 +26,27 @@ static const struct ieee80211_iface_combination if_comb[] = {
                .max_interfaces = MT7921_MAX_INTERFACES,
                .num_different_channels = 1,
                .beacon_int_infra_match = true,
+       },
+};
+
+static const struct ieee80211_iface_limit if_limits_chanctx[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP),
+       }
+};
+
+static const struct ieee80211_iface_combination if_comb_chanctx[] = {
+       {
+               .limits = if_limits_chanctx,
+               .n_limits = ARRAY_SIZE(if_limits_chanctx),
+               .max_interfaces = 2,
+               .num_different_channels = 2,
+               .beacon_int_infra_match = false,
        }
 };
 
@@ -66,17 +87,19 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
        hw->sta_data_size = sizeof(struct mt7921_sta);
        hw->vif_data_size = sizeof(struct mt7921_vif);
 
-       if (dev->fw_features & MT7921_FW_CAP_CNM)
+       if (dev->fw_features & MT7921_FW_CAP_CNM) {
                wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
-       else
+               wiphy->iface_combinations = if_comb_chanctx;
+               wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx);
+       } else {
                wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
-
-       wiphy->iface_combinations = if_comb;
+               wiphy->iface_combinations = if_comb;
+               wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+       }
        wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
                          WIPHY_FLAG_4ADDR_STATION);
        wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                 BIT(NL80211_IFTYPE_AP);
-       wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
        wiphy->max_remain_on_channel_duration = 5000;
        wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
        wiphy->max_scan_ssids = 4;
index eeab756240a24dc1dd364245d37203a634a9026d..443a4a49bc9eb5675ef726374217986853b97bf4 100644 (file)
@@ -168,14 +168,6 @@ static void
 mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy,
                            struct mt76_rx_status *status, u8 chfreq)
 {
-       if (!test_bit(MT76_HW_SCANNING, &mphy->state) &&
-           !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) &&
-           !test_bit(MT76_STATE_ROC, &mphy->state)) {
-               status->freq = mphy->chandef.chan->center_freq;
-               status->band = mphy->chandef.chan->band;
-               return;
-       }
-
        if (chfreq > 180) {
                status->band = NL80211_BAND_6GHZ;
                chfreq = (chfreq - 181) * 4 + 1;
index 012c92d49f49afe13f5d1ba5ba4d09fab0397151..41df17efdb3a76068330f9edec78bd9c03a02071 100644 (file)
@@ -858,7 +858,7 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 
        if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
                mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid,
-                                           true, NULL);
+                                           true, mvif->ctx);
 
        mt7921_mac_wtbl_update(dev, msta->wcid.idx,
                               MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -891,7 +891,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
                if (!sta->tdls)
                        mt76_connac_mcu_uni_add_bss(&dev->mphy, vif,
                                                    &mvif->sta.wcid, false,
-                                                   NULL);
+                                                   mvif->ctx);
        }
 
        spin_lock_bh(&dev->sta_poll_lock);
@@ -1645,7 +1645,7 @@ mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        mt7921_mutex_acquire(dev);
 
        err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
-                                         true, NULL);
+                                         true, mvif->ctx);
        if (err)
                goto out;
 
@@ -1677,12 +1677,108 @@ mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                goto out;
 
        mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false,
-                                   NULL);
+                                   mvif->ctx);
 
 out:
        mt7921_mutex_release(dev);
 }
 
+static int
+mt7921_add_chanctx(struct ieee80211_hw *hw,
+                  struct ieee80211_chanctx_conf *ctx)
+{
+       return 0;
+}
+
+static void
+mt7921_remove_chanctx(struct ieee80211_hw *hw,
+                     struct ieee80211_chanctx_conf *ctx)
+{
+}
+
+static void mt7921_ctx_iter(void *priv, u8 *mac,
+                           struct ieee80211_vif *vif)
+{
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct ieee80211_chanctx_conf *ctx = priv;
+
+       if (ctx != mvif->ctx)
+               return;
+
+       mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx);
+}
+
+static void
+mt7921_change_chanctx(struct ieee80211_hw *hw,
+                     struct ieee80211_chanctx_conf *ctx,
+                     u32 changed)
+{
+       struct mt7921_phy *phy = mt7921_hw_phy(hw);
+
+       mt7921_mutex_acquire(phy->dev);
+       ieee80211_iterate_active_interfaces(phy->mt76->hw,
+                                           IEEE80211_IFACE_ITER_ACTIVE,
+                                           mt7921_ctx_iter, ctx);
+       mt7921_mutex_release(phy->dev);
+}
+
+static int
+mt7921_assign_vif_chanctx(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_bss_conf *link_conf,
+                         struct ieee80211_chanctx_conf *ctx)
+{
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct mt7921_dev *dev = mt7921_hw_dev(hw);
+
+       mutex_lock(&dev->mt76.mutex);
+       mvif->ctx = ctx;
+       mutex_unlock(&dev->mt76.mutex);
+
+       return 0;
+}
+
+static void
+mt7921_unassign_vif_chanctx(struct ieee80211_hw *hw,
+                           struct ieee80211_vif *vif,
+                           struct ieee80211_bss_conf *link_conf,
+                           struct ieee80211_chanctx_conf *ctx)
+{
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct mt7921_dev *dev = mt7921_hw_dev(hw);
+
+       mutex_lock(&dev->mt76.mutex);
+       mvif->ctx = NULL;
+       mutex_unlock(&dev->mt76.mutex);
+}
+
+static void mt7921_mgd_prepare_tx(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_prep_tx_info *info)
+{
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct mt7921_dev *dev = mt7921_hw_dev(hw);
+       u16 duration = info->duration ? info->duration :
+                      jiffies_to_msecs(HZ);
+
+       mt7921_mutex_acquire(dev);
+       mt7921_set_roc(mvif->phy, mvif, mvif->ctx->def.chan, duration,
+                      MT7921_ROC_REQ_JOIN);
+       mt7921_mutex_release(dev);
+}
+
+static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_prep_tx_info *info)
+{
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct mt7921_dev *dev = mt7921_hw_dev(hw);
+
+       mt7921_mutex_acquire(dev);
+       mt7921_abort_roc(mvif->phy, mvif);
+       mt7921_mutex_release(dev);
+}
+
 const struct ieee80211_ops mt7921_ops = {
        .tx = mt7921_tx,
        .start = mt7921_start,
@@ -1735,6 +1831,13 @@ const struct ieee80211_ops mt7921_ops = {
        .set_sar_specs = mt7921_set_sar_specs,
        .remain_on_channel = mt7921_remain_on_channel,
        .cancel_remain_on_channel = mt7921_cancel_remain_on_channel,
+       .add_chanctx = mt7921_add_chanctx,
+       .remove_chanctx = mt7921_remove_chanctx,
+       .change_chanctx = mt7921_change_chanctx,
+       .assign_vif_chanctx = mt7921_assign_vif_chanctx,
+       .unassign_vif_chanctx = mt7921_unassign_vif_chanctx,
+       .mgd_prepare_tx = mt7921_mgd_prepare_tx,
+       .mgd_complete_tx = mt7921_mgd_complete_tx,
 };
 EXPORT_SYMBOL_GPL(mt7921_ops);
 
index 4f0147e40bc34985950d3a2a567729640e3e24bf..ac70a978dbed91bc6cfe64311e4e0b1995d20d56 100644 (file)
@@ -171,6 +171,7 @@ struct mt7921_vif {
        struct ewma_rssi rssi;
 
        struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+       struct ieee80211_chanctx_conf *ctx;
 };
 
 struct mib_stats {
index 32ad26ef3a6890cf2e09053aed52d7c427a19551..28342ec940f06332ceb7dc4586aea0c3ab589062 100644 (file)
@@ -297,6 +297,13 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
        if (!(features & MT7921_FW_CAP_CNM)) {
                ops->remain_on_channel = NULL;
                ops->cancel_remain_on_channel = NULL;
+               ops->add_chanctx = NULL;
+               ops->remove_chanctx = NULL;
+               ops->change_chanctx = NULL;
+               ops->assign_vif_chanctx = NULL;
+               ops->unassign_vif_chanctx = NULL;
+               ops->mgd_prepare_tx = NULL;
+               ops->mgd_complete_tx = NULL;
        }
 
        mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops);
index e07a8fb87421f006b737f82a116e145ca8722c34..8ce4252b8ae7c74ffd436210a7194eacaef331c0 100644 (file)
@@ -140,6 +140,13 @@ static int mt7921s_probe(struct sdio_func *func,
        if (!(features & MT7921_FW_CAP_CNM)) {
                ops->remain_on_channel = NULL;
                ops->cancel_remain_on_channel = NULL;
+               ops->add_chanctx = NULL;
+               ops->remove_chanctx = NULL;
+               ops->change_chanctx = NULL;
+               ops->assign_vif_chanctx = NULL;
+               ops->unassign_vif_chanctx = NULL;
+               ops->mgd_prepare_tx = NULL;
+               ops->mgd_complete_tx = NULL;
        }
 
        mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);
index 8a49d3de207385bbbaeef148b76d83b492cbe33d..5321d20dcdcbfe6133bc1c800aa8417fafef5083 100644 (file)
@@ -218,6 +218,13 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
        if (!(features & MT7921_FW_CAP_CNM)) {
                ops->remain_on_channel = NULL;
                ops->cancel_remain_on_channel = NULL;
+               ops->add_chanctx = NULL;
+               ops->remove_chanctx = NULL;
+               ops->change_chanctx = NULL;
+               ops->assign_vif_chanctx = NULL;
+               ops->unassign_vif_chanctx = NULL;
+               ops->mgd_prepare_tx = NULL;
+               ops->mgd_complete_tx = NULL;
        }
 
        ops->stop = mt7921u_stop;