mt76: mt7915: register per-phy HE capabilities for each interface
authorRyder Lee <ryder.lee@mediatek.com>
Fri, 24 Apr 2020 19:32:30 +0000 (03:32 +0800)
committerFelix Fietkau <nbd@nbd.name>
Tue, 12 May 2020 17:52:35 +0000 (19:52 +0200)
The capabilities for the HE interfaces are generated from the capabilities
reported by the firmware.

This should move to common file once we got other HE devices support.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/init.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 abce37ca925229a98c12032f2f0a6c44b16e61e8..bb8325e2edbd49664763071a5d0304916430c500 100644 (file)
@@ -239,6 +239,194 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
        hw->max_tx_fragments = 4;
 }
 
+static void
+mt7915_gen_ppe_thresh(u8 *he_ppet)
+{
+       int ru, nss, max_nss = 1, max_ru = 3;
+       u8 bit = 7, ru_bit_mask = 0x7;
+       u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71};
+
+       he_ppet[0] = max_nss & IEEE80211_PPE_THRES_NSS_MASK;
+       he_ppet[0] |= (ru_bit_mask <<
+                      IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) &
+                       IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK;
+
+       for (nss = 0; nss <= max_nss; nss++) {
+               for (ru = 0; ru < max_ru; ru++) {
+                       u8 val;
+                       int i;
+
+                       if (!(ru_bit_mask & BIT(ru)))
+                               continue;
+
+                       val = (ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) &
+                              0x3f;
+                       val = ((val >> 3) & 0x7) | ((val & 0x7) << 3);
+                       for (i = 5; i >= 0; i--) {
+                               he_ppet[bit / 8] |=
+                                       ((val >> i) & 0x1) << ((bit % 8));
+                               bit++;
+                       }
+               }
+       }
+}
+
+static int
+mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
+                   struct ieee80211_sband_iftype_data *data)
+{
+       int i, idx = 0;
+       int nss = hweight8(phy->chainmask);
+       u16 mcs_map = 0;
+
+       for (i = 0; i < 8; i++) {
+               if (i < nss)
+                       mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2));
+               else
+                       mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+       }
+
+       for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
+               struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap;
+               struct ieee80211_he_cap_elem *he_cap_elem =
+                               &he_cap->he_cap_elem;
+               struct ieee80211_he_mcs_nss_supp *he_mcs =
+                               &he_cap->he_mcs_nss_supp;
+
+               switch (i) {
+               case NL80211_IFTYPE_STATION:
+               case NL80211_IFTYPE_AP:
+#ifdef CONFIG_MAC80211_MESH
+               case NL80211_IFTYPE_MESH_POINT:
+#endif
+                       break;
+               default:
+                       continue;
+               }
+
+               data[idx].types_mask = BIT(i);
+               he_cap->has_he = true;
+
+               he_cap_elem->mac_cap_info[0] =
+                       IEEE80211_HE_MAC_CAP0_HTC_HE;
+               he_cap_elem->mac_cap_info[1] =
+                       IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US |
+                       IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1;
+               he_cap_elem->mac_cap_info[2] =
+                       IEEE80211_HE_MAC_CAP2_BSR;
+               he_cap_elem->mac_cap_info[3] =
+                       IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
+                       IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED;
+               he_cap_elem->mac_cap_info[4] =
+                       IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU;
+
+               if (band == NL80211_BAND_2GHZ)
+                       he_cap_elem->phy_cap_info[0] =
+                               IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
+               else if (band == NL80211_BAND_5GHZ)
+                       he_cap_elem->phy_cap_info[0] =
+                               IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+                               IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+                               IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
+
+               he_cap_elem->phy_cap_info[1] =
+                       IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
+               he_cap_elem->phy_cap_info[2] =
+                       IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
+                       IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
+                       IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
+
+               /* TODO: TxBF & MU & MESH */
+
+               switch (i) {
+               case NL80211_IFTYPE_AP:
+                       he_cap_elem->mac_cap_info[0] |=
+                               IEEE80211_HE_MAC_CAP0_TWT_RES;
+                       he_cap_elem->mac_cap_info[4] |=
+                               IEEE80211_HE_MAC_CAP4_BQR;
+                       he_cap_elem->phy_cap_info[3] |=
+                               IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
+                               IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
+                       he_cap_elem->phy_cap_info[6] |=
+                               IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
+                       he_cap_elem->phy_cap_info[9] |=
+                               IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       he_cap_elem->mac_cap_info[0] |=
+                               IEEE80211_HE_MAC_CAP0_TWT_REQ;
+                       he_cap_elem->mac_cap_info[3] |=
+                               IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED;
+
+                       if (band == NL80211_BAND_2GHZ)
+                               he_cap_elem->phy_cap_info[0] |=
+                                       IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
+                       else if (band == NL80211_BAND_5GHZ)
+                               he_cap_elem->phy_cap_info[0] |=
+                                       IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G;
+
+                       he_cap_elem->phy_cap_info[1] |=
+                               IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A;
+                       he_cap_elem->phy_cap_info[8] |=
+                               IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
+                               IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
+                               IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
+                       he_cap_elem->phy_cap_info[9] |=
+                               IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
+                       break;
+#ifdef CONFIG_MAC80211_MESH
+               case NL80211_IFTYPE_MESH_POINT:
+                       break;
+#endif
+               }
+
+               he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
+               he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
+               he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map);
+               he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map);
+               he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map);
+               he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map);
+
+               memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
+               if (he_cap_elem->phy_cap_info[6] &
+                   IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
+                       mt7915_gen_ppe_thresh(he_cap->ppe_thres);
+               } else {
+                       he_cap_elem->phy_cap_info[9] |=
+                               IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
+               }
+               idx++;
+       }
+
+       return idx;
+}
+
+void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
+{
+       struct ieee80211_sband_iftype_data *data;
+       struct ieee80211_supported_band *band;
+       struct mt76_dev *mdev = &phy->dev->mt76;
+       int n;
+
+       if (mdev->cap.has_2ghz) {
+               data = phy->iftype[NL80211_BAND_2GHZ];
+               n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
+
+               band = &phy->mt76->sband_2g.sband;
+               band->iftype_data = data;
+               band->n_iftype_data = n;
+       }
+
+       if (mdev->cap.has_5ghz) {
+               data = phy->iftype[NL80211_BAND_5GHZ];
+               n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
+
+               band = &phy->mt76->sband_5g.sband;
+               band->iftype_data = data;
+               band->n_iftype_data = n;
+       }
+}
+
 static void
 mt7915_cap_dbdc_enable(struct mt7915_dev *dev)
 {
@@ -256,6 +444,7 @@ mt7915_cap_dbdc_enable(struct mt7915_dev *dev)
        dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask;
 
        mt76_set_stream_caps(&dev->mt76, true);
+       mt7915_set_stream_he_caps(&dev->phy);
 }
 
 static void
@@ -271,6 +460,7 @@ mt7915_cap_dbdc_disable(struct mt7915_dev *dev)
        dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask;
 
        mt76_set_stream_caps(&dev->mt76, true);
+       mt7915_set_stream_he_caps(&dev->phy);
 }
 
 int mt7915_register_ext_phy(struct mt7915_dev *dev)
index 231bae4184ca4d844e5c7a107680abc14a84e051..09722569202629cf5ceb21c9f949dea280c22973 100644 (file)
@@ -691,6 +691,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
        phy->chainmask = tx_ant;
 
        mt76_set_stream_caps(&dev->mt76, true);
+       mt7915_set_stream_he_caps(phy);
 
        mutex_unlock(&dev->mt76.mutex);
 
index b275d18e5d9ba3858dd014aabf008f721ab3dc66..47c0ff8f41bf52efaa213a9584c68029cfee203c 100644 (file)
@@ -137,11 +137,13 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif,
 {
        struct ieee80211_sta_ht_cap *ht_cap;
        struct ieee80211_sta_vht_cap *vht_cap;
+       const struct ieee80211_sta_he_cap *he_cap;
        u8 mode = 0;
 
        if (sta) {
                ht_cap = &sta->ht_cap;
                vht_cap = &sta->vht_cap;
+               he_cap = &sta->he_cap;
        } else {
                struct ieee80211_supported_band *sband;
 
@@ -152,6 +154,7 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif,
 
                ht_cap = &sband->ht_cap;
                vht_cap = &sband->vht_cap;
+               he_cap = ieee80211_get_he_iftype_cap(sband, vif->type);
        }
 
        if (band == NL80211_BAND_2GHZ) {
@@ -159,6 +162,9 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif,
 
                if (ht_cap->ht_supported)
                        mode |= PHY_MODE_GN;
+
+               if (he_cap->has_he)
+                       mode |= PHY_MODE_AX_24G;
        } else if (band == NL80211_BAND_5GHZ) {
                mode |= PHY_MODE_A;
 
@@ -167,6 +173,9 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif,
 
                if (vht_cap->vht_supported)
                        mode |= PHY_MODE_AC;
+
+               if (he_cap->has_he)
+                       mode |= PHY_MODE_AX_5G;
        }
 
        return mode;
index d9c9aab7e6dc026a3e158872fe784b8a8d6ce01e..c71161aec767b133c3d5774fd4ee2b0e5c52df93 100644 (file)
@@ -815,6 +815,9 @@ enum {
 #define PHY_MODE_GN                    BIT(3)
 #define PHY_MODE_AN                    BIT(4)
 #define PHY_MODE_AC                    BIT(5)
+#define PHY_MODE_AX_24G                        BIT(6)
+#define PHY_MODE_AX_5G                 BIT(7)
+#define PHY_MODE_AX_6G                 BIT(8)
 
 #define MODE_CCK                       BIT(0)
 #define MODE_OFDM                      BIT(1)
index 6d3fde7f635ab255ee96a8a25d95625fa4c4d4bd..92a6bf746d73b3baaa04e87e2b4a6c26e8167581 100644 (file)
@@ -122,6 +122,8 @@ struct mt7915_phy {
        struct mt76_phy *mt76;
        struct mt7915_dev *dev;
 
+       struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES];
+
        u32 rxfilter;
        u32 vif_mask;
        u32 omac_mask;
@@ -443,6 +445,7 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev,
                          struct mt76_txwi_cache *txwi);
 int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force);
 int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);
+void mt7915_set_stream_he_caps(struct mt7915_phy *phy);
 void mt7915_update_channel(struct mt76_dev *mdev);
 int mt7915_init_debugfs(struct mt7915_dev *dev);