]> www.infradead.org Git - users/hch/configfs.git/commitdiff
wifi: iwlwifi: support fast resume
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 18 Jun 2024 16:44:03 +0000 (19:44 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 26 Jun 2024 08:28:49 +0000 (10:28 +0200)
This will allow to suspend / resume the system without resetting the
firmware. This will allow to reduce the resume time.
In case the fast_resume fails, stop the device and bring it up from
scratch.

Raise the timeout for the D3_END notification since in some iterations,
it took 240ms.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20240618194245.03b8d2801044.I613d17c712de7a0d611cde4e14f37ebbe0c3c964@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/tt.c

index 54f4acbbd05bd4d2f7e8a25e748c02c432025de1..b4d650583ac27e2ba6d24166a64ec6998cd003cb 100644 (file)
@@ -2493,6 +2493,9 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
                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]);
@@ -3049,7 +3052,7 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
        if (iwl_mvm_rt_status(mvm->trans,
                              mvm->trans->dbg.lmac_error_event_table[0],
                              &err_id)) {
-               if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+               if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) {
                        struct cfg80211_wowlan_wakeup wakeup = {
                                .rfkill_release = true,
                        };
@@ -3366,7 +3369,7 @@ static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test)
        return ret;
 }
 
-#define IWL_MVM_D3_NOTIF_TIMEOUT (HZ / 5)
+#define IWL_MVM_D3_NOTIF_TIMEOUT (HZ / 3)
 
 static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm,
                                 struct iwl_d3_data *d3_data)
@@ -3377,12 +3380,22 @@ static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm,
                WIDE_ID(SCAN_GROUP, OFFLOAD_MATCH_INFO_NOTIF),
                WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION)
        };
+       static const u16 d3_fast_resume_notif[] = {
+               WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION)
+       };
        struct iwl_notification_wait wait_d3_notif;
        int ret;
 
-       iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif,
-                                  d3_resume_notif, ARRAY_SIZE(d3_resume_notif),
-                                  iwl_mvm_wait_d3_notif, d3_data);
+       if (mvm->fast_resume)
+               iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif,
+                                          d3_fast_resume_notif,
+                                          ARRAY_SIZE(d3_fast_resume_notif),
+                                          iwl_mvm_wait_d3_notif, d3_data);
+       else
+               iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif,
+                                          d3_resume_notif,
+                                          ARRAY_SIZE(d3_resume_notif),
+                                          iwl_mvm_wait_d3_notif, d3_data);
 
        ret = iwl_mvm_resume_firmware(mvm, d3_data->test);
        if (ret) {
@@ -3567,6 +3580,68 @@ void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
        device_set_wakeup_enable(mvm->trans->dev, enabled);
 }
 
+void iwl_mvm_fast_suspend(struct iwl_mvm *mvm)
+{
+       struct iwl_d3_manager_config d3_cfg_cmd_data = {};
+       int ret;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       IWL_DEBUG_WOWLAN(mvm, "Starting fast suspend flow\n");
+
+       mvm->fast_resume = true;
+       set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
+
+       WARN_ON(iwl_mvm_power_update_device(mvm));
+       mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;
+       ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SEND_IN_D3,
+                                  sizeof(d3_cfg_cmd_data), &d3_cfg_cmd_data);
+       if (ret)
+               IWL_ERR(mvm,
+                       "fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret);
+
+       WARN_ON(iwl_mvm_power_update_mac(mvm));
+
+       ret = iwl_trans_d3_suspend(mvm->trans, false, false);
+       if (ret)
+               IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret);
+}
+
+int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
+{
+       struct iwl_d3_data d3_data = {
+               .notif_expected =
+                       IWL_D3_NOTIF_D3_END_NOTIF,
+       };
+       int ret;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       IWL_DEBUG_WOWLAN(mvm, "Starting the fast resume flow\n");
+
+       mvm->last_reset_or_resume_time_jiffies = jiffies;
+       iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
+
+       if (iwl_mvm_check_rt_status(mvm, NULL)) {
+               set_bit(STATUS_FW_ERROR, &mvm->trans->status);
+               iwl_mvm_dump_nic_error_log(mvm);
+               iwl_dbg_tlv_time_point(&mvm->fwrt,
+                                      IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);
+               iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
+                                       false, 0);
+               return -ENODEV;
+       }
+       ret = iwl_mvm_d3_notif_wait(mvm, &d3_data);
+       clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
+       mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+       mvm->fast_resume = false;
+
+       if (ret)
+               IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret);
+
+       return ret;
+}
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
 {
index 1c1f9816cf5e617f3ac0eb7225d8c44ec2516bda..3cffd03c6013f51cd02b755d47dc726d9707cf1f 100644 (file)
@@ -1222,6 +1222,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 
 int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
 {
+       bool fast_resume = false;
        int ret;
 
        lockdep_assert_held(&mvm->mutex);
@@ -1247,6 +1248,30 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
                mvm->nvm_data = NULL;
        }
 
+#ifdef CONFIG_PM
+       /* fast_resume will be cleared by iwl_mvm_fast_resume */
+       fast_resume = mvm->fast_resume;
+
+       if (fast_resume) {
+               ret = iwl_mvm_fast_resume(mvm);
+               if (ret) {
+                       iwl_mvm_stop_device(mvm);
+                       /* iwl_mvm_up() will be called further down */
+               } else {
+                       /*
+                        * We clear IWL_MVM_STATUS_FIRMWARE_RUNNING upon
+                        * mac_down() so that debugfs will stop honoring
+                        * requests after we flush all the workers.
+                        * Set the IWL_MVM_STATUS_FIRMWARE_RUNNING bit again
+                        * now that we are back. This is a bit abusing the
+                        * flag since the firmware wasn't really ever stopped,
+                        * but this still serves the purpose.
+                        */
+                       set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
+               }
+       }
+#endif /* CONFIG_PM */
+
        if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status)) {
                /*
                 * Now convert the HW_RESTART_REQUESTED flag to IN_HW_RESTART
@@ -1257,7 +1282,10 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
                /* Clean up some internal and mac80211 state on restart */
                iwl_mvm_restart_cleanup(mvm);
        }
-       ret = iwl_mvm_up(mvm);
+
+       /* we also want to load the firmware if fast_resume failed */
+       if (!fast_resume || ret)
+               ret = iwl_mvm_up(mvm);
 
        iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_POST_INIT,
                               NULL);
@@ -1340,7 +1368,7 @@ void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,
        }
 }
 
-void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
+void __iwl_mvm_mac_stop(struct iwl_mvm *mvm, bool suspend)
 {
        lockdep_assert_held(&mvm->mutex);
 
@@ -1356,7 +1384,11 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
        if (!iwl_mvm_has_new_station_api(mvm->fw))
                iwl_mvm_rm_aux_sta(mvm);
 
-       iwl_mvm_stop_device(mvm);
+       if (suspend &&
+           mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
+               iwl_mvm_fast_suspend(mvm);
+       else
+               iwl_mvm_stop_device(mvm);
 
        iwl_mvm_async_handlers_purge(mvm);
        /* async_handlers_list is empty and will stay empty: HW is stopped */
@@ -1425,7 +1457,7 @@ void iwl_mvm_mac_stop(struct ieee80211_hw *hw, bool suspend)
        iwl_mvm_mei_set_sw_rfkill_state(mvm);
 
        mutex_lock(&mvm->mutex);
-       __iwl_mvm_mac_stop(mvm);
+       __iwl_mvm_mac_stop(mvm, suspend);
        mutex_unlock(&mvm->mutex);
 
        /*
index 4ced1e51c9082ce18969bf28d2073eb4167ece99..3692f62ee89577b3bc8f861e58fb8e775c8db720 100644 (file)
@@ -1161,6 +1161,7 @@ struct iwl_mvm {
        struct ieee80211_channel **nd_channels;
        int n_nd_channels;
        bool net_detect;
+       bool fast_resume;
        u8 offload_tid;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        bool d3_wake_sysassert;
@@ -1739,7 +1740,7 @@ struct iwl_rate_info {
        u8 ieee;        /* MAC header:  IWL_RATE_6M_IEEE, etc. */
 };
 
-void __iwl_mvm_mac_stop(struct iwl_mvm *mvm);
+void __iwl_mvm_mac_stop(struct iwl_mvm *mvm, bool suspend);
 int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
 
 /******************
@@ -2261,11 +2262,22 @@ extern const struct file_operations iwl_dbgfs_d3_test_ops;
 #ifdef CONFIG_PM
 void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,
                                 struct ieee80211_vif *vif);
+void iwl_mvm_fast_suspend(struct iwl_mvm *mvm);
+int iwl_mvm_fast_resume(struct iwl_mvm *mvm);
 #else
 static inline void
 iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
 }
+
+static inline void iwl_mvm_fast_suspend(struct iwl_mvm *mvm)
+{
+}
+
+static inline int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
+{
+       return 0;
+}
 #endif
 void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
                                struct iwl_wowlan_config_cmd *cmd);
index 45b431ffbc977d51251abe5e9bf8b23dbb92c83f..718184be19b3249500957f240aa49df79c995496 100644 (file)
@@ -299,7 +299,7 @@ static void check_exit_ctkill(struct work_struct *work)
 
        ret = iwl_mvm_get_temp(mvm, &temp);
 
-       __iwl_mvm_mac_stop(mvm);
+       __iwl_mvm_mac_stop(mvm, false);
 
        if (ret)
                goto reschedule;