]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: iwlwifi: mvm: add EHT radiotap info based on rate_n_flags
authorMordechay Goodstein <mordechay.goodstein@intel.com>
Sun, 5 Mar 2023 12:16:20 +0000 (14:16 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 7 Mar 2023 19:15:17 +0000 (20:15 +0100)
rate_n_flags is always present in the data so at least give all of
the information we can extract from rate_n_flags

Signed-off-by: Mordechay Goodstein <mordechay.goodstein@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230305124407.b1c7d49ad35e.Ie2412ac6f88700aa3767ff95ffb52a806b13b7ce@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c

index ddacd5b45aeab6829999fa8af582511237931d93..1d372a09ebb4a396a5e30d4bf89c4d0b7d64d1de 100644 (file)
@@ -449,11 +449,16 @@ enum {
  *     1                       2xLTF+0.8us
  *     2                       2xLTF+1.6us
  *     3                       4xLTF+3.2us
- * HE TRIG:
+ * HE-EHT TRIG:
  *     0                       1xLTF+1.6us
  *     1                       2xLTF+1.6us
  *     2                       4xLTF+3.2us
  *     3                       (does not occur)
+ * EHT MU:
+ *     0                       2xLTF+0.8us
+ *     1                       2xLTF+1.6us
+ *     2                       4xLTF+0.8us
+ *     3                       4xLTF+3.2us
  */
 #define RATE_MCS_HE_GI_LTF_POS         20
 #define RATE_MCS_HE_GI_LTF_MSK_V1              (3 << RATE_MCS_HE_GI_LTF_POS)
@@ -546,12 +551,17 @@ enum {
 /*
  * Bits 13-11: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz, (4) 320MHz
  */
-#define RATE_MCS_CHAN_WIDTH_MSK                        (0x7 << RATE_MCS_CHAN_WIDTH_POS)
-#define RATE_MCS_CHAN_WIDTH_20                 (0 << RATE_MCS_CHAN_WIDTH_POS)
-#define RATE_MCS_CHAN_WIDTH_40                 (1 << RATE_MCS_CHAN_WIDTH_POS)
-#define RATE_MCS_CHAN_WIDTH_80                 (2 << RATE_MCS_CHAN_WIDTH_POS)
-#define RATE_MCS_CHAN_WIDTH_160                        (3 << RATE_MCS_CHAN_WIDTH_POS)
-#define RATE_MCS_CHAN_WIDTH_320                        (4 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_MSK                (0x7 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_20_VAL     0
+#define RATE_MCS_CHAN_WIDTH_20         (RATE_MCS_CHAN_WIDTH_20_VAL << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_40_VAL     1
+#define RATE_MCS_CHAN_WIDTH_40         (RATE_MCS_CHAN_WIDTH_40_VAL << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_80_VAL     2
+#define RATE_MCS_CHAN_WIDTH_80         (RATE_MCS_CHAN_WIDTH_80_VAL << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_160_VAL    3
+#define RATE_MCS_CHAN_WIDTH_160                (RATE_MCS_CHAN_WIDTH_160_VAL << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_320_VAL    4
+#define RATE_MCS_CHAN_WIDTH_320                (RATE_MCS_CHAN_WIDTH_320_VAL << RATE_MCS_CHAN_WIDTH_POS)
 
 /* Bit 15-14: Antenna selection:
  * Bit 14: Ant A active
index 206b56ca8db85327a8e31131ae3e15c1c3c400b4..aa72910f8ff2b5cb2ef9396976fd78c4a540388c 100644 (file)
@@ -1456,6 +1456,137 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
        }
 }
 
+static void iwl_mvm_rx_eht(struct iwl_mvm *mvm, struct sk_buff *skb,
+                          struct iwl_mvm_rx_phy_data *phy_data,
+                          int queue)
+{
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+
+       struct ieee80211_radiotap_eht *eht;
+       struct ieee80211_radiotap_eht_usig *usig;
+
+       u32 rate_n_flags = phy_data->rate_n_flags;
+       u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
+       /* EHT and HE have the same valus for LTF */
+       u8 ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN;
+       u16 phy_info = phy_data->phy_info;
+       u32 bw;
+
+       /* u32 for 1 user_info */
+       eht = iwl_mvm_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT,
+                                      sizeof(*eht) + sizeof(u32));
+
+       usig = iwl_mvm_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG,
+                                       sizeof(*usig));
+       rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END;
+       usig->common |=
+               cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN);
+
+       /* specific handling for 320MHz */
+       bw = FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, rate_n_flags);
+       if (bw == RATE_MCS_CHAN_WIDTH_320_VAL)
+               bw += FIELD_GET(IWL_RX_PHY_DATA0_EHT_BW320_SLOT,
+                               le32_to_cpu(phy_data->d0));
+
+       usig->common |= cpu_to_le32
+               (FIELD_PREP(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW, bw));
+
+       /* report the AMPDU-EOF bit on single frames */
+       if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
+               rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
+               rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
+               if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
+                       rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
+       }
+
+       /* update aggregation data for monitor sake on default queue */
+       if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) &&
+           (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
+               bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
+
+               /* toggle is switched whenever new aggregation starts */
+               if (toggle_bit != mvm->ampdu_toggle) {
+                       rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
+                       if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
+                               rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
+               }
+       }
+
+       /* TODO: fill usig info (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) */
+
+#define CHECK_TYPE(F)                                                  \
+       BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F !=        \
+                    (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS))
+
+       CHECK_TYPE(SU);
+       CHECK_TYPE(EXT_SU);
+       CHECK_TYPE(MU);
+       CHECK_TYPE(TRIG);
+
+       switch (FIELD_GET(RATE_MCS_HE_GI_LTF_MSK, rate_n_flags)) {
+       case 0:
+               if (he_type == RATE_MCS_HE_TYPE_TRIG) {
+                       rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_1_6;
+                       ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X;
+               } else {
+                       rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_0_8;
+                       ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X;
+               }
+               break;
+       case 1:
+               rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_1_6;
+               ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X;
+               break;
+       case 2:
+               ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
+               if (he_type == RATE_MCS_HE_TYPE_TRIG)
+                       rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_3_2;
+               else
+                       rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_0_8;
+               break;
+       case 3:
+               if (he_type != RATE_MCS_HE_TYPE_TRIG) {
+                       ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
+                       rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_3_2;
+               }
+               break;
+       default:
+               /* nothing here */
+               break;
+       }
+
+       if (ltf != IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN) {
+               eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_GI);
+               eht->data[0] |= cpu_to_le32
+                       (FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_LTF,
+                                   ltf) |
+                        FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_GI,
+                                   rx_status->eht.gi));
+       }
+
+       eht->user_info[0] |= cpu_to_le32
+               (IEEE80211_RADIOTAP_EHT_USER_INFO_MCS_KNOWN |
+                IEEE80211_RADIOTAP_EHT_USER_INFO_CODING_KNOWN |
+                IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_KNOWN_O |
+                IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_KNOWN_O |
+                IEEE80211_RADIOTAP_EHT_USER_INFO_DATA_FOR_USER);
+
+       if (rate_n_flags & RATE_MCS_BF_MSK)
+               eht->user_info[0] |=
+                       cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_BEAMFORMING_O);
+
+       if (rate_n_flags & RATE_MCS_LDPC_MSK)
+               eht->user_info[0] |=
+                       cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_CODING);
+
+       eht->user_info[0] |= cpu_to_le32
+               (FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_MCS,
+                           FIELD_GET(RATE_VHT_MCS_RATE_CODE_MSK,
+                                     rate_n_flags)) |
+                FIELD_PREP(IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O,
+                           FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags)));
+}
+
 static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
                          struct iwl_mvm_rx_phy_data *phy_data,
                          int queue)
@@ -1703,6 +1834,10 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,
        iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags,
                                    phy_data->energy_a, phy_data->energy_b);
 
+       /* using TLV format and must be after all fixed len fields */
+       if (format == RATE_MCS_EHT_MSK)
+               iwl_mvm_rx_eht(mvm, skb, phy_data, queue);
+
        if (unlikely(mvm->monitor_on))
                iwl_mvm_add_rtap_sniffer_config(mvm, skb);