wifi: iwlwifi: mvm: support new versions of the wowlan APIs
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 28 Oct 2024 11:54:49 +0000 (13:54 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 7 Nov 2024 13:42:29 +0000 (14:42 +0100)
Add support version 7 of wowlan_config_cmd and version 5 of
iwl_wowlan_info_notif

This version is mainly a cleanup of the previous version.
Two fields were removed as the device already handled this data.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20241028135215.d2afdf720073.I9901c8c4ad4508135d019efa213b1430acc70746@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/offloading.c

index ffee7927cf26c980dfff5328b37544ed3a37c2e8..c2362bc786b28f2c9ae5a58a9875d10841cdefb2 100644 (file)
@@ -368,7 +368,7 @@ enum iwl_wowlan_flags {
 };
 
 /**
- * struct iwl_wowlan_config_cmd - WoWLAN configuration (versions 5 and 6)
+ * struct iwl_wowlan_config_cmd_v6 - WoWLAN configuration (versions 5 and 6)
  * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters
  * @non_qos_seq: non-QoS sequence counter to use next.
  *               Reserved if the struct has version >= 6.
@@ -380,7 +380,7 @@ enum iwl_wowlan_flags {
  * @sta_id: station ID for wowlan.
  * @reserved: reserved
  */
-struct iwl_wowlan_config_cmd {
+struct iwl_wowlan_config_cmd_v6 {
        __le32 wakeup_filter;
        __le16 non_qos_seq;
        __le16 qos_seq[8];
@@ -390,7 +390,27 @@ struct iwl_wowlan_config_cmd {
        u8 flags;
        u8 sta_id;
        u8 reserved;
-} __packed; /* WOWLAN_CONFIG_API_S_VER_5 */
+} __packed; /* WOWLAN_CONFIG_API_S_VER_6 */
+
+/**
+ * struct iwl_wowlan_config_cmd - WoWLAN configuration
+ * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters
+ * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down
+ * @is_11n_connection: indicates HT connection
+ * @offloading_tid: TID reserved for firmware use
+ * @flags: extra flags, see &enum iwl_wowlan_flags
+ * @sta_id: station ID for wowlan.
+ * @reserved: reserved
+ */
+struct iwl_wowlan_config_cmd {
+       __le32 wakeup_filter;
+       u8 wowlan_ba_teardown_tids;
+       u8 is_11n_connection;
+       u8 offloading_tid;
+       u8 flags;
+       u8 sta_id;
+       u8 reserved[3];
+} __packed; /* WOWLAN_CONFIG_API_S_VER_7 */
 
 #define IWL_NUM_RSC    16
 #define WOWLAN_KEY_MAX_SIZE    32
@@ -890,7 +910,7 @@ struct iwl_wowlan_mlo_gtk {
 } __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */
 
 /**
- * struct iwl_wowlan_info_notif - WoWLAN information notification
+ * struct iwl_wowlan_info_notif_v4 - WoWLAN information notification
  * @gtk: GTK data
  * @igtk: IGTK data
  * @bigtk: BIGTK data
@@ -910,7 +930,7 @@ struct iwl_wowlan_mlo_gtk {
  * @reserved2: reserved
  * @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4
  */
-struct iwl_wowlan_info_notif {
+struct iwl_wowlan_info_notif_v4 {
        struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
        struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
        struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM];
@@ -929,6 +949,45 @@ struct iwl_wowlan_info_notif {
        struct iwl_wowlan_mlo_gtk mlo_gtks[];
 } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */
 
+/**
+ * struct iwl_wowlan_info_notif - WoWLAN information notification
+ * @gtk: GTK data
+ * @igtk: IGTK data
+ * @bigtk: BIGTK data
+ * @replay_ctr: GTK rekey replay counter
+ * @pattern_number: number of the matched patterns
+ * @qos_seq_ctr: QoS sequence counters to use next
+ * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason
+ * @num_of_gtk_rekeys: number of GTK rekeys
+ * @transmitted_ndps: number of transmitted neighbor discovery packets
+ * @received_beacons: number of received beacons
+ * @tid_tear_down: bit mask of tids whose BA sessions were closed
+ *     in suspend state
+ * @station_id: station id
+ * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs
+ *     following this notif
+ * @tid_offloaded_tx: tid used by the firmware to transmit data packets
+ *     while in wowlan
+ * @mlo_gtks: array of GTKs of size num_mlo_link_keys
+ */
+struct iwl_wowlan_info_notif {
+       struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM];
+       __le64 replay_ctr;
+       __le16 pattern_number;
+       __le16 qos_seq_ctr;
+       __le32 wakeup_reasons;
+       __le32 num_of_gtk_rekeys;
+       __le32 transmitted_ndps;
+       __le32 received_beacons;
+       u8 tid_tear_down;
+       u8 station_id;
+       u8 num_mlo_link_keys;
+       u8 tid_offloaded_tx;
+       struct iwl_wowlan_mlo_gtk mlo_gtks[];
+} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */
+
 /**
  * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification
  * @wake_packet_length: wakeup packet length
index 9f41b9af52693c2a6db9850de5c7053e5c18c916..fae9eabfa56eeb29fe736606e93714e1eb9eabe0 100644 (file)
@@ -922,7 +922,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
 static int
 iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
                          struct cfg80211_wowlan *wowlan,
-                         struct iwl_wowlan_config_cmd *wowlan_config_cmd,
+                         struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd,
                          struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
                          struct ieee80211_sta *ap_sta)
 {
@@ -948,7 +948,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
                wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret);
        }
 
-       iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);
+       if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 7)
+               iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);
 
        if (wowlan->disconnect)
                wowlan_config_cmd->wakeup_filter |=
@@ -1122,7 +1123,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
 static int
 iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
                      struct cfg80211_wowlan *wowlan,
-                     struct iwl_wowlan_config_cmd *wowlan_config_cmd,
+                     struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd_v6,
                      struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
                      struct iwl_mvm_vif_link_info *mvm_link,
                      struct ieee80211_sta *ap_sta)
@@ -1131,7 +1132,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
        bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
                                         IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
-       mvm->offload_tid = wowlan_config_cmd->offloading_tid;
+       mvm->offload_tid = wowlan_config_cmd_v6->offloading_tid;
 
        if (!unified_image) {
                ret = iwl_mvm_switch_to_d3(mvm);
@@ -1147,9 +1148,26 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
        if (ret)
                return ret;
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
-                                  sizeof(*wowlan_config_cmd),
-                                  wowlan_config_cmd);
+       if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) > 6) {
+               struct iwl_wowlan_config_cmd wowlan_config_cmd = {
+                       .wakeup_filter = wowlan_config_cmd_v6->wakeup_filter,
+                       .wowlan_ba_teardown_tids =
+                               wowlan_config_cmd_v6->wowlan_ba_teardown_tids,
+                       .is_11n_connection =
+                               wowlan_config_cmd_v6->is_11n_connection,
+                       .offloading_tid = wowlan_config_cmd_v6->offloading_tid,
+                       .flags = wowlan_config_cmd_v6->flags,
+                       .sta_id = wowlan_config_cmd_v6->sta_id,
+               };
+
+               ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
+                                          sizeof(wowlan_config_cmd),
+                                          &wowlan_config_cmd);
+       } else {
+               ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
+                                          sizeof(*wowlan_config_cmd_v6),
+                                          wowlan_config_cmd_v6);
+       }
        if (ret)
                return ret;
 
@@ -1302,7 +1320,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 
                mvm->net_detect = true;
        } else {
-               struct iwl_wowlan_config_cmd wowlan_config_cmd = {
+               struct iwl_wowlan_config_cmd_v6 wowlan_config_cmd = {
                        .offloading_tid = 0,
                };
 
@@ -1423,6 +1441,7 @@ struct iwl_wowlan_status_data {
        u16 non_qos_seq_ctr;
        u16 qos_seq_ctr[8];
        u8 tid_tear_down;
+       u8 tid_offloaded_tx;
 
        struct {
                /* including RX MIC key for TKIP */
@@ -2472,7 +2491,64 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status,
 static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
                                            struct iwl_wowlan_info_notif *data,
                                            struct iwl_wowlan_status_data *status,
-                                           u32 len, bool has_mlo_keys)
+                                           u32 len)
+{
+       u32 expected_len = sizeof(*data) +
+               data->num_mlo_link_keys * sizeof(status->mlo_keys[0]);
+
+       if (!data) {
+               IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n");
+               status = NULL;
+               return;
+       }
+
+       if (len < expected_len) {
+               IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
+               status = NULL;
+               return;
+       }
+
+       if (mvm->fast_resume)
+               return;
+
+       iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc);
+       iwl_mvm_convert_gtk_v3(status, data->gtk);
+       iwl_mvm_convert_igtk(status, &data->igtk[0]);
+       iwl_mvm_convert_bigtk(status, data->bigtk);
+       status->replay_ctr = le64_to_cpu(data->replay_ctr);
+       status->pattern_number = le16_to_cpu(data->pattern_number);
+       status->tid_offloaded_tx = data->tid_offloaded_tx;
+       if (IWL_FW_CHECK(mvm,
+                        data->tid_offloaded_tx >=
+                        ARRAY_SIZE(status->qos_seq_ctr),
+                        "tid_offloaded_tx is out of bound %d\n",
+                        data->tid_offloaded_tx))
+               data->tid_offloaded_tx = 0;
+       status->qos_seq_ctr[data->tid_offloaded_tx] =
+               le16_to_cpu(data->qos_seq_ctr);
+       status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons);
+       status->num_of_gtk_rekeys =
+               le32_to_cpu(data->num_of_gtk_rekeys);
+       status->received_beacons = le32_to_cpu(data->received_beacons);
+       status->tid_tear_down = data->tid_tear_down;
+
+       if (data->num_mlo_link_keys) {
+               status->num_mlo_keys = data->num_mlo_link_keys;
+               if (IWL_FW_CHECK(mvm,
+                                status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS,
+                                "Too many mlo keys: %d, max %d\n",
+                                status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS))
+                       status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS;
+               memcpy(status->mlo_keys, data->mlo_gtks,
+                      status->num_mlo_keys * sizeof(status->mlo_keys[0]));
+       }
+}
+
+static void
+iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm,
+                                  struct iwl_wowlan_info_notif_v4 *data,
+                                  struct iwl_wowlan_status_data *status,
+                                  u32 len, bool has_mlo_keys)
 {
        u32 i;
        u32 expected_len = sizeof(*data);
@@ -2744,6 +2820,10 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int link_id = vif->active_links ? __ffs(vif->active_links) : 0;
        struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id];
+       int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw,
+                                                     PROT_OFFLOAD_GROUP,
+                                                     WOWLAN_INFO_NOTIFICATION,
+                                                     IWL_FW_CMD_VER_UNKNOWN);
 
        if (WARN_ON(!mvm_link))
                goto out_unlock;
@@ -2758,11 +2838,14 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
        if (!mvm_ap_sta)
                goto out_unlock;
 
-       for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
-               u16 seq = status->qos_seq_ctr[i];
-               /* firmware stores last-used value, we store next value */
-               seq += 0x10;
-               mvm_ap_sta->tid_data[i].seq_number = seq;
+       /* firmware stores last-used value, we store next value */
+       if (wowlan_info_ver >= 5) {
+               mvm_ap_sta->tid_data[status->tid_offloaded_tx].seq_number =
+                       status->qos_seq_ctr[status->tid_offloaded_tx] + 0x10;
+       } else {
+               for (i = 0; i < IWL_MAX_TID_COUNT; i++)
+                       mvm_ap_sta->tid_data[i].seq_number =
+                               status->qos_seq_ctr[i] + 0x10;
        }
 
        if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
@@ -3246,13 +3329,19 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
                        iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2,
                                                           d3_data->status,
                                                           len);
+               } else if (wowlan_info_ver < 5) {
+                       struct iwl_wowlan_info_notif_v4 *notif =
+                               (void *)pkt->data;
+
+                       iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif,
+                                                          d3_data->status, len,
+                                                          wowlan_info_ver > 3);
                } else {
                        struct iwl_wowlan_info_notif *notif =
                                (void *)pkt->data;
 
                        iwl_mvm_parse_wowlan_info_notif(mvm, notif,
-                                                       d3_data->status, len,
-                                                       wowlan_info_ver > 3);
+                                                       d3_data->status, len);
                }
 
                d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO;
index 9d3072ac8c58df6f26851b47c49e24e1756cd8c3..2ad615293c75a1c46ae163f36e71974707b8f9f9 100644 (file)
@@ -2333,7 +2333,7 @@ static inline int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
 }
 #endif
 void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
-                               struct iwl_wowlan_config_cmd *cmd);
+                               struct iwl_wowlan_config_cmd_v6 *cmd);
 int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                               struct ieee80211_vif *vif,
                               bool disable_offloading,
index 1eb21fe861e5fddf53bb72efdec15b5e4f5ab0b8..15d4369678a2a414d56091e7e8727acf0901e696 100644 (file)
@@ -10,7 +10,7 @@
 #include "mvm.h"
 
 void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
-                               struct iwl_wowlan_config_cmd *cmd)
+                               struct iwl_wowlan_config_cmd_v6 *cmd)
 {
        int i;