wifi: iwlwifi: mvm: parse FW frame metadata for EHT sniffer mode
authorMordechay Goodstein <mordechay.goodstein@intel.com>
Sun, 5 Mar 2023 12:16:25 +0000 (14:16 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 7 Mar 2023 19:15:18 +0000 (20:15 +0100)
In EHT sniffer mode DW4 is all used for sniffer data (unlike we have in
HE mode), so move the full DW4 into a union, and we extract the new data5
used for parsing USIG info and set all to radiotap TLVs with the
extracted data.

Also parse OFDM_RX_VECTOR_USIG_A1_OUT and OFDM_RX_VECTOR_USIG_A2_OUT for
rx_no_data notification.

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.557d3870753b.I4e9fa4d21900a187753529d46956ba2a7ee75fda@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c

index 0f190266fffd42840dc7c724439eaa71e6c5460a..97e946e70279a249f9b749eb6d7b8b239c0c8998 100644 (file)
@@ -674,22 +674,31 @@ struct iwl_rx_mpdu_desc {
         * @mac_phy_idx: MAC/PHY index
         */
        u8 mac_phy_idx;
-       /* DW4 - carries csum data only when rpa_en == 1 */
-       /**
-        * @raw_csum: raw checksum (alledgedly unreliable)
-        */
-       __le16 raw_csum;
-
+       /* DW4 */
        union {
+               struct {
+                       /* carries csum data only when rpa_en == 1 */
+                       /**
+                        * @raw_csum: raw checksum (alledgedly unreliable)
+                        */
+                       __le16 raw_csum;
+
+                       union {
+                               /**
+                                * @l3l4_flags: &enum iwl_rx_l3l4_flags
+                                */
+                               __le16 l3l4_flags;
+
+                               /**
+                                * @phy_data4: depends on info type, see phy_data1
+                                */
+                               __le16 phy_data4;
+                       };
+               };
                /**
-                * @l3l4_flags: &enum iwl_rx_l3l4_flags
-                */
-               __le16 l3l4_flags;
-
-               /**
-                * @phy_data4: depends on info type, see phy_data1
+                * @phy_eht_data4: depends on info type, see phy_data1
                 */
-               __le16 phy_data4;
+               __le32 phy_eht_data4;
        };
        /* DW5 */
        /**
@@ -744,6 +753,35 @@ struct iwl_rx_mpdu_desc {
 #define RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK        0x38000000
 #define RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK        0x00f00000
 
+/* content of OFDM_RX_VECTOR_USIG_A1_OUT */
+enum iwl_rx_usig_a1 {
+       IWL_RX_USIG_A1_ENHANCED_WIFI_VER_ID     = 0x00000007,
+       IWL_RX_USIG_A1_BANDWIDTH                = 0x00000038,
+       IWL_RX_USIG_A1_UL_FLAG                  = 0x00000040,
+       IWL_RX_USIG_A1_BSS_COLOR                = 0x00001f80,
+       IWL_RX_USIG_A1_TXOP_DURATION            = 0x000fe000,
+       IWL_RX_USIG_A1_DISREGARD                = 0x01f00000,
+       IWL_RX_USIG_A1_VALIDATE                 = 0x02000000,
+       IWL_RX_USIG_A1_EHT_BW320_SLOT           = 0x04000000,
+       IWL_RX_USIG_A1_EHT_TYPE                 = 0x18000000,
+       IWL_RX_USIG_A1_RDY                      = 0x80000000,
+};
+
+/* content of OFDM_RX_VECTOR_USIG_A2_EHT_OUT */
+enum iwl_rx_usig_a2_eht {
+       IWL_RX_USIG_A2_EHT_PPDU_TYPE            = 0x00000003,
+       IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2    = 0x00000004,
+       IWL_RX_USIG_A2_EHT_PUNC_CHANNEL         = 0x000000f8,
+       IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B8    = 0x00000100,
+       IWL_RX_USIG_A2_EHT_SIG_MCS              = 0x00000600,
+       IWL_RX_USIG_A2_EHT_SIG_SYM_NUM          = 0x0000f800,
+       IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_1 = 0x000f0000,
+       IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_2 = 0x00f00000,
+       IWL_RX_USIG_A2_EHT_TRIG_USIG2_DISREGARD = 0x1f000000,
+       IWL_RX_USIG_A2_EHT_CRC_OK               = 0x40000000,
+       IWL_RX_USIG_A2_EHT_RDY                  = 0x80000000,
+};
+
 /**
  * struct iwl_rx_no_data - RX no data descriptor
  * @info: 7:0 frame type, 15:8 RX error type
@@ -781,7 +819,7 @@ struct iwl_rx_no_data {
  * @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type.
  *     for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT
  *     for HE: OFDM_RX_VECTOR_HE_SIGA1_OUT, OFDM_RX_VECTOR_HE_SIGA2_OUT
- *     for EHT: OFDM_RX_VECTOR_USIG_A1_OUT, OFDM_RX_VECTOR_USIG_A2_OUT,
+ *     for EHT: OFDM_RX_VECTOR_USIG_A1_OUT, OFDM_RX_VECTOR_USIG_A2_EHT_OUT,
  *     OFDM_RX_VECTOR_EHT_OUT, OFDM_RX_VECTOR_EHT_USER_FIELD_OUT
  */
 struct iwl_rx_no_data_ver_3 {
index c069e81bf3f1b271e6f4720691e2acbfc80efaa0..1334c96098a57f1c3e02b6bf8666516590c13657 100644 (file)
@@ -1177,8 +1177,10 @@ static void iwl_mvm_flip_address(u8 *addr)
 
 struct iwl_mvm_rx_phy_data {
        enum iwl_rx_phy_info_type info_type;
-       __le32 d0, d1, d2, d3;
+       __le32 d0, d1, d2, d3, eht_d4, d5;
        __le16 d4;
+       bool with_data;
+       __le32 rx_vec[4];
 
        u32 rate_n_flags;
        u32 gp2_on_air_rise;
@@ -1459,6 +1461,119 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
 #define LE32_DEC_ENC(value, dec_bits, enc_bits) \
        le32_encode_bits(le32_get_bits(value, dec_bits), enc_bits)
 
+#define IWL_MVM_ENC_USIG_VALUE_MASK(usig, in_value, dec_bits, enc_bits) do { \
+       typeof(enc_bits) _enc_bits = enc_bits; \
+       typeof(usig) _usig = usig; \
+       (_usig)->mask |= cpu_to_le32(_enc_bits); \
+       (_usig)->value |= LE32_DEC_ENC(in_value, dec_bits, _enc_bits); \
+} while (0)
+
+static void iwl_mvm_decode_eht_ext_mu(struct iwl_mvm *mvm,
+                                     struct iwl_mvm_rx_phy_data *phy_data,
+                                     struct ieee80211_rx_status *rx_status,
+                                     struct ieee80211_radiotap_eht *eht,
+                                     struct ieee80211_radiotap_eht_usig *usig)
+{
+       __le32 data1 = phy_data->d1;
+
+       if (phy_data->with_data) {
+               __le32 data4 = phy_data->eht_d4;
+               __le32 data5 = phy_data->d5;
+
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
+                                           IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
+                                           IWL_RX_PHY_DATA5_EHT_MU_PUNC_CH_CODE,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, data4,
+                                           IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS);
+               IWL_MVM_ENC_USIG_VALUE_MASK
+                       (usig, data1, IWL_RX_PHY_DATA1_EHT_MU_NUM_SIG_SYM_USIGA2,
+                        IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS);
+
+       } else {
+               __le32 usig_a1 = phy_data->rx_vec[0];
+               __le32 usig_a2 = phy_data->rx_vec[1];
+
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a1,
+                                           IWL_RX_USIG_A1_DISREGARD,
+                                           IEEE80211_RADIOTAP_EHT_USIG1_MU_B20_B24_DISREGARD);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a1,
+                                           IWL_RX_USIG_A1_VALIDATE,
+                                           IEEE80211_RADIOTAP_EHT_USIG1_MU_B25_VALIDATE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_PPDU_TYPE,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B0_B1_PPDU_TYPE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B2_VALIDATE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_PUNC_CHANNEL,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B3_B7_PUNCTURED_INFO);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B8,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B8_VALIDATE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_SIG_MCS,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B9_B10_SIG_MCS);
+               IWL_MVM_ENC_USIG_VALUE_MASK
+                       (usig, usig_a2, IWL_RX_USIG_A2_EHT_SIG_SYM_NUM,
+                        IEEE80211_RADIOTAP_EHT_USIG2_MU_B11_B15_EHT_SIG_SYMBOLS);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_CRC_OK,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_MU_B16_B19_CRC);
+       }
+}
+
+static void iwl_mvm_decode_eht_ext_tb(struct iwl_mvm *mvm,
+                                     struct iwl_mvm_rx_phy_data *phy_data,
+                                     struct ieee80211_rx_status *rx_status,
+                                     struct ieee80211_radiotap_eht *eht,
+                                     struct ieee80211_radiotap_eht_usig *usig)
+{
+       if (phy_data->with_data) {
+               __le32 data5 = phy_data->d5;
+
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
+                                           IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
+                                           IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE1,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1);
+
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, data5,
+                                           IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE2,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2);
+       } else {
+               __le32 usig_a1 = phy_data->rx_vec[0];
+               __le32 usig_a2 = phy_data->rx_vec[1];
+
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a1,
+                                           IWL_RX_USIG_A1_DISREGARD,
+                                           IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_PPDU_TYPE,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_USIG2_VALIDATE_B2,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B2_VALIDATE);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_1,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B3_B6_SPATIAL_REUSE_1);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_TRIG_SPATIAL_REUSE_2,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B7_B10_SPATIAL_REUSE_2);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_TRIG_USIG2_DISREGARD,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B11_B15_DISREGARD);
+               IWL_MVM_ENC_USIG_VALUE_MASK(usig, usig_a2,
+                                           IWL_RX_USIG_A2_EHT_CRC_OK,
+                                           IEEE80211_RADIOTAP_EHT_USIG2_TB_B16_B19_CRC);
+       }
+}
+
 static void iwl_mvm_decode_eht_ru(struct iwl_mvm *mvm,
                                  struct ieee80211_rx_status *rx_status,
                                  struct ieee80211_radiotap_eht *eht)
@@ -1537,6 +1652,7 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm,
 {
        __le32 data0 = phy_data->d0;
        __le32 data1 = phy_data->d1;
+       __le32 usig_a1 = phy_data->rx_vec[0];
        u8 info_type = phy_data->info_type;
 
        /* Not in EHT range */
@@ -1547,12 +1663,21 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm,
        usig->common |= cpu_to_le32
                (IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN |
                 IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN);
-       usig->common |= LE32_DEC_ENC(data0,
-                                    IWL_RX_PHY_DATA0_EHT_UPLINK,
-                                    IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL);
-       usig->common |= LE32_DEC_ENC(data0,
-                                    IWL_RX_PHY_DATA0_EHT_BSS_COLOR_MASK,
-                                    IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN);
+       if (phy_data->with_data) {
+               usig->common |= LE32_DEC_ENC(data0,
+                                            IWL_RX_PHY_DATA0_EHT_UPLINK,
+                                            IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL);
+               usig->common |= LE32_DEC_ENC(data0,
+                                            IWL_RX_PHY_DATA0_EHT_BSS_COLOR_MASK,
+                                            IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR);
+       } else {
+               usig->common |= LE32_DEC_ENC(usig_a1,
+                                            IWL_RX_USIG_A1_UL_FLAG,
+                                            IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL);
+               usig->common |= LE32_DEC_ENC(usig_a1,
+                                            IWL_RX_USIG_A1_BSS_COLOR,
+                                            IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR);
+       }
 
        eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE);
        eht->data[0] |= LE32_DEC_ENC(data0,
@@ -1571,8 +1696,13 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm,
        iwl_mvm_decode_eht_ru(mvm, rx_status, eht);
 
        usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN);
-       usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_TXOP_DUR_MASK,
-                                    IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP);
+       if (phy_data->with_data)
+               usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_TXOP_DUR_MASK,
+                                            IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP);
+       else
+               usig->common |= LE32_DEC_ENC(usig_a1, IWL_RX_USIG_A1_TXOP_DURATION,
+                                            IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP);
+
        eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_LDPC_EXTRA_SYM_OM);
        eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_LDPC_EXT_SYM,
                                     IEEE80211_RADIOTAP_EHT_DATA0_LDPC_EXTRA_SYM_OM);
@@ -1593,6 +1723,23 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm,
        usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN);
        usig->common |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PHY_VER,
                                     IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER);
+
+       /*
+        * TODO: what about TB - IWL_RX_PHY_DATA1_EHT_TB_PILOT_TYPE,
+        *                       IWL_RX_PHY_DATA1_EHT_TB_LOW_SS
+        */
+
+       eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF);
+       eht->data[0] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM,
+                                    IEEE80211_RADIOTAP_EHT_DATA0_EHT_LTF);
+
+       if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT ||
+           info_type == IWL_RX_PHY_INFO_TYPE_EHT_TB)
+               iwl_mvm_decode_eht_ext_tb(mvm, phy_data, rx_status, eht, usig);
+
+       if (info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT ||
+           info_type == IWL_RX_PHY_INFO_TYPE_EHT_MU)
+               iwl_mvm_decode_eht_ext_mu(mvm, phy_data, rx_status, eht, usig);
 }
 
 static void iwl_mvm_rx_eht(struct iwl_mvm *mvm, struct sk_buff *skb,
@@ -2077,6 +2224,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                phy_data.d1 = desc->v3.phy_data1;
                phy_data.d2 = desc->v3.phy_data2;
                phy_data.d3 = desc->v3.phy_data3;
+               phy_data.eht_d4 = desc->phy_eht_data4;
+               phy_data.d5 = desc->v3.phy_data5;
        } else {
                phy_data.rate_n_flags = le32_to_cpu(desc->v1.rate_n_flags);
                phy_data.channel = desc->v1.channel;
@@ -2106,6 +2255,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                return;
        }
 
+       phy_data.with_data = true;
        phy_data.phy_info = le16_to_cpu(desc->phy_info);
        phy_data.d4 = desc->phy_data4;
 
@@ -2368,6 +2518,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
        phy_data.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK);
        phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK);
        phy_data.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK);
+       phy_data.with_data = false;
 
        if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
                                    RX_NO_DATA_NOTIF, 0) < 2) {
@@ -2386,6 +2537,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
                    sizeof(struct iwl_rx_no_data_ver_3)))
                /* invalid len for ver 3 */
                        return;
+               memcpy(phy_data.rx_vec, desc->rx_vec, sizeof(phy_data.rx_vec));
        } else {
                if (format == RATE_MCS_EHT_MSK)
                        /* no support for EHT before version 3 API */