mt76: mt7915: add support for 6G in-band discovery
authorMeiChia Chiu <MeiChia.Chiu@mediatek.com>
Tue, 26 Apr 2022 02:23:35 +0000 (10:23 +0800)
committerFelix Fietkau <nbd@nbd.name>
Fri, 13 May 2022 07:39:35 +0000 (09:39 +0200)
Add offloading FILS discovery and unsolicited broadcast probe response support.

Reviewed-by: Ryder Lee <ryder.lee@mediatek.com>
Signed-off-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/init.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/mt7915/main.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h

index 1e777affc2d87f969b918b7b4e2f56e6451eb414..01169853355e9a4d5e0b1afcd377a6c2ed2bf8b5 100644 (file)
@@ -351,6 +351,8 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
+       wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
+       wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
 
        if (!mdev->dev->of_node ||
            !of_property_read_bool(mdev->dev->of_node,
index a493162b4e8c0ff2ab3ab8a6660f51137a51ac30..086244d9be76687e6af5090a4ca06dc6202b1507 100644 (file)
@@ -1177,7 +1177,7 @@ out:
 
 void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
                           struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
-                          struct ieee80211_key_conf *key, bool beacon)
+                          struct ieee80211_key_conf *key, u32 changed)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_vif *vif = info->control.vif;
@@ -1188,6 +1188,10 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
        bool mcast = false;
        u16 tx_count = 15;
        u32 val;
+       bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+                                   BSS_CHANGED_BEACON_ENABLED));
+       bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+                                        BSS_CHANGED_FILS_DISCOVERY));
 
        if (vif) {
                struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
@@ -1200,7 +1204,10 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
        if (ext_phy && dev->mt76.phy2)
                mphy = dev->mt76.phy2;
 
-       if (beacon) {
+       if (inband_disc) {
+               p_fmt = MT_TX_TYPE_FW;
+               q_idx = MT_LMAC_ALTX0;
+       } else if (beacon) {
                p_fmt = MT_TX_TYPE_FW;
                q_idx = MT_LMAC_BCN0;
        } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
@@ -1308,8 +1315,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
                return id;
 
        pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
-       mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key,
-                             false);
+       mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, 0);
 
        txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
        for (i = 0; i < nbuf; i++) {
@@ -2008,7 +2014,8 @@ mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_AP:
-               mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
+               mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon,
+                                     BSS_CHANGED_BEACON_ENABLED);
                break;
        default:
                break;
index 78bf5ffa75766f67faa988eff8fdb4510409647a..710ca757fb5258db870c44d5413fde109392d5dc 100644 (file)
@@ -622,8 +622,10 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
                mt7915_update_bss_color(hw, vif, &info->he_bss_color);
 
        if (changed & (BSS_CHANGED_BEACON |
-                      BSS_CHANGED_BEACON_ENABLED))
-               mt7915_mcu_add_beacon(hw, vif, info->enable_beacon);
+                      BSS_CHANGED_BEACON_ENABLED |
+                      BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+                      BSS_CHANGED_FILS_DISCOVERY))
+               mt7915_mcu_add_beacon(hw, vif, info->enable_beacon, changed);
 
        mutex_unlock(&dev->mt76.mutex);
 }
@@ -636,7 +638,7 @@ mt7915_channel_switch_beacon(struct ieee80211_hw *hw,
        struct mt7915_dev *dev = mt7915_hw_dev(hw);
 
        mutex_lock(&dev->mt76.mutex);
-       mt7915_mcu_add_beacon(hw, vif, true);
+       mt7915_mcu_add_beacon(hw, vif, true, BSS_CHANGED_BEACON);
        mutex_unlock(&dev->mt76.mutex);
 }
 
index 07c1a15e735d53e2d8a0c18a52aebb1595e9cccb..b7e2b365356c782647a0f72ce3c62c465728d29f 100644 (file)
@@ -1892,6 +1892,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
        u8 *buf;
        int len = sizeof(*cont) + MT_TXD_SIZE + skb->len;
 
+       len = (len & 0x3) ? ((len | 0x3) + 1) : len;
        tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT,
                                           len, &bcn->sub_ntlv, &bcn->len);
 
@@ -1910,7 +1911,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
 
        buf = (u8 *)tlv + sizeof(*cont);
        mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
-                             true);
+                             BSS_CHANGED_BEACON);
        memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
 }
 
@@ -1992,8 +1993,71 @@ mt7915_mcu_beacon_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif,
        }
 }
 
-int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
-                         struct ieee80211_vif *vif, int en)
+static void
+mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+                               struct sk_buff *rskb, struct bss_info_bcn *bcn,
+                               u32 changed)
+{
+#define OFFLOAD_TX_MODE_SU     BIT(0)
+#define OFFLOAD_TX_MODE_MU     BIT(1)
+       struct ieee80211_hw *hw = mt76_hw(dev);
+       struct mt7915_phy *phy = mt7915_hw_phy(hw);
+       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+       struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
+       enum nl80211_band band = chandef->chan->band;
+       struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+       struct bss_info_inband_discovery *discov;
+       struct ieee80211_tx_info *info;
+       struct sk_buff *skb = NULL;
+       struct tlv *tlv;
+       bool ext_phy = phy != &dev->phy;
+       u8 *buf, interval;
+       int len;
+
+       if (changed & BSS_CHANGED_FILS_DISCOVERY &&
+           vif->bss_conf.fils_discovery.max_interval) {
+               interval = vif->bss_conf.fils_discovery.max_interval;
+               skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
+       } else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
+                  vif->bss_conf.unsol_bcast_probe_resp_interval) {
+               interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
+               skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
+       }
+
+       if (!skb)
+               return;
+
+       info = IEEE80211_SKB_CB(skb);
+       info->control.vif = vif;
+       info->band = band;
+
+       if (ext_phy)
+               info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
+
+       len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
+       len = (len & 0x3) ? ((len | 0x3) + 1) : len;
+
+       tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV,
+                                          len, &bcn->sub_ntlv, &bcn->len);
+       discov = (struct bss_info_inband_discovery *)tlv;
+       discov->tx_mode = OFFLOAD_TX_MODE_SU;
+       /* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
+       discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
+       discov->tx_interval = interval;
+       discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
+       discov->enable = true;
+
+       buf = (u8 *)tlv + sizeof(*discov);
+
+       mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
+                             changed);
+       memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
+
+       dev_kfree_skb(skb);
+}
+
+int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                         int en, u32 changed)
 {
 #define MAX_BEACON_SIZE 512
        struct mt7915_dev *dev = mt7915_hw_dev(hw);
@@ -2044,6 +2108,11 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
        mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
        dev_kfree_skb(skb);
 
+       if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP ||
+           changed & BSS_CHANGED_FILS_DISCOVERY)
+               mt7915_mcu_beacon_inband_discov(dev, vif, rskb,
+                                               bcn, changed);
+
 out:
        return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
                                     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
index 0c40e44699375a93fde504dc998f4323d790c8fe..5abde482a97ff1f76920a510568b183a7aacb933 100644 (file)
@@ -404,11 +404,23 @@ struct bss_info_bcn_cont {
        __le16 pkt_len;
 } __packed __aligned(4);
 
+struct bss_info_inband_discovery {
+       __le16 tag;
+       __le16 len;
+       u8 tx_type;
+       u8 tx_mode;
+       u8 tx_interval;
+       u8 enable;
+       __le16 rsv;
+       __le16 prob_rsp_len;
+} __packed __aligned(4);
+
 enum {
        BSS_INFO_BCN_CSA,
        BSS_INFO_BCN_BCC,
        BSS_INFO_BCN_MBSSID,
        BSS_INFO_BCN_CONTENT,
+       BSS_INFO_BCN_DISCOV,
        BSS_INFO_BCN_MAX
 };
 
@@ -490,6 +502,7 @@ enum {
 #define MT7915_BEACON_UPDATE_SIZE      (sizeof(struct sta_req_hdr) +   \
                                         sizeof(struct bss_info_bcn_cntdwn) + \
                                         sizeof(struct bss_info_bcn_mbss) + \
-                                        sizeof(struct bss_info_bcn_cont))
+                                        sizeof(struct bss_info_bcn_cont) + \
+                                        sizeof(struct bss_info_inband_discovery))
 
 #endif
index fdd989f0bb992941530addb881cd603129788ca7..269e56f851b0bbaf12b25a74605d13564218b0db 100644 (file)
@@ -469,7 +469,7 @@ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
 int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
                                struct cfg80211_he_bss_color *he_bss_color);
 int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                         int enable);
+                         int enable, u32 changed);
 int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
                             bool enable);
 int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
@@ -556,7 +556,7 @@ void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
 void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy);
 void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
                           struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
-                          struct ieee80211_key_conf *key, bool beacon);
+                          struct ieee80211_key_conf *key, u32 changed);
 void mt7915_mac_set_timing(struct mt7915_phy *phy);
 int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);