wifi: iwlwifi: mvm: Add support for d3 end notification
authorHaim Dreyfuss <haim.dreyfuss@intel.com>
Tue, 6 Sep 2022 13:42:14 +0000 (16:42 +0300)
committerGregory Greenman <gregory.greenman@intel.com>
Sun, 18 Sep 2022 11:40:15 +0000 (14:40 +0300)
Due to IMR, when host returns from hibernate, commands cannot
be sent as part of the resume flow, and so after ending
d3 the FW needs to send notifications instead of responses.
This notification indicates whether a fw reset is required.

Signed-off-by: Yedidya Benshimol <yedidya.ben.shimol@intel.com>
Signed-off-by: Haim Dreyfuss <haim.dreyfuss@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20220906161827.898ecba881b2.I13eb69bb5af08b9ac33043647eaed6b8d50e8659@changeid
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
drivers/net/wireless/intel/iwlwifi/fw/api/offload.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c

index 5588f6d65813f569e421086b14975cd016624016..df0833890e55aae68b4df0384922c0a1f0718fe9 100644 (file)
@@ -817,6 +817,14 @@ struct iwl_wowlan_wake_pkt_notif {
        u8 wake_packet[1];
 } __packed; /* WOWLAN_WAKE_PKT_NTFY_API_S_VER_1 */
 
+/**
+ * struct iwl_mvm_d3_end_notif -  d3 end notification
+ * @flags: See &enum iwl_d0i3_flags
+ */
+struct iwl_mvm_d3_end_notif {
+       __le32 flags;
+} __packed;
+
 /* TODO: NetDetect API */
 
 #endif /* __iwl_fw_api_d3_h__ */
index 1a1b7ac78309899326db56bd8eb4f9d18cee8a9b..a0123f81f5d8a301243c545bfcebb4799cfd6a34 100644 (file)
@@ -22,6 +22,11 @@ enum iwl_prot_offload_subcmd_ids {
         */
        WOWLAN_INFO_NOTIFICATION = 0xFD,
 
+       /**
+        * @D3_END_NOTIFICATION: End D3 state notification
+        */
+       D3_END_NOTIFICATION = 0xFE,
+
        /**
         * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif
         */
index 77e70899c46ef54547d59b73f189eeea5e5bc005..3a593f6175fdfa0cc5a8e52d9820bd600ef7d0ec 100644 (file)
@@ -2517,16 +2517,21 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
  * enum iwl_d3_notif - d3 notifications
  * @IWL_D3_NOTIF_WOWLAN_INFO: WOWLAN_INFO_NOTIF was received
  * @IWL_D3_NOTIF_WOWLAN_WAKE_PKT: WOWLAN_WAKE_PKT_NOTIF was received
+ * @IWL_D3_NOTIF_PROT_OFFLOAD: PROT_OFFLOAD_NOTIF was received
+ * @IWL_D3_NOTIF_D3_END_NOTIF: D3_END_NOTIF was received
  */
 enum iwl_d3_notif {
        IWL_D3_NOTIF_WOWLAN_INFO =      BIT(0),
        IWL_D3_NOTIF_WOWLAN_WAKE_PKT =  BIT(1),
+       IWL_D3_NOTIF_PROT_OFFLOAD =     BIT(2),
+       IWL_D3_NOTIF_D3_END_NOTIF =     BIT(3)
 };
 
 /* manage d3 resume data */
 struct iwl_d3_data {
        struct iwl_wowlan_status_data *status;
        bool test;
+       u32 d3_end_flags;
        u32 notif_expected;     /* bitmap - see &enum iwl_d3_notif */
        u32 notif_received;     /* bitmap - see &enum iwl_d3_notif */
 };
@@ -2670,6 +2675,14 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
 
                break;
        }
+       case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): {
+               struct iwl_mvm_d3_end_notif *notif = (void *)pkt->data;
+
+               d3_data->d3_end_flags = __le32_to_cpu(notif->flags);
+               d3_data->notif_received |= IWL_D3_NOTIF_D3_END_NOTIF;
+
+               break;
+       }
        default:
                WARN_ON(1);
        }
@@ -2686,7 +2699,8 @@ static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm,
 {
        static const u16 d3_resume_notif[] = {
                WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION),
-               WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_WAKE_PKT_NOTIFICATION)
+               WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_WAKE_PKT_NOTIFICATION),
+               WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION)
        };
        struct iwl_notification_wait wait_d3_notif;
        int ret;
@@ -2718,7 +2732,9 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        enum iwl_d3_status d3_status;
        struct iwl_d3_data d3_data = {
                .test = test,
-               .notif_expected = IWL_D3_NOTIF_WOWLAN_INFO,
+               .notif_expected =
+                       IWL_D3_NOTIF_WOWLAN_INFO |
+                       IWL_D3_NOTIF_D3_END_NOTIF,
        };
        bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
                                         IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
@@ -2788,6 +2804,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        /* after the successful handshake, we're out of D3 */
        mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
 
+       /* when reset is required we can't send these following commands */
+       if (d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)
+               goto query_wakeup_reasons;
+
        /*
         * Query the current location and source from the D3 firmware so we
         * can play it back when we re-intiailize the D0 firmware
@@ -2812,6 +2832,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
                                        false);
        }
 
+query_wakeup_reasons:
        iwl_mvm_choose_query_wakeup_reasons(mvm, vif, &d3_data, d3_data.test);
        /* has unlocked the mutex, so skip that */
        goto out;
@@ -2832,9 +2853,14 @@ out:
                if (d0i3_first)
                        return 0;
 
-               ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
-               if (!ret)
+               if (!iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
+                                            D3_END_NOTIFICATION, 0)) {
+                       ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
+                       if (!ret)
+                               return 0;
+               } else if (!(d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)) {
                        return 0;
+               }
        }
 
        /*
index 9c8adb0c2acf2596da27213c460b11299f9414d1..3eb59b958801b6ee0a18b26bae4601686397dd10 100644 (file)
@@ -576,6 +576,7 @@ static const struct iwl_hcmd_names iwl_mvm_location_names[] = {
 static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = {
        HCMD_NAME(WOWLAN_WAKE_PKT_NOTIFICATION),
        HCMD_NAME(WOWLAN_INFO_NOTIFICATION),
+       HCMD_NAME(D3_END_NOTIFICATION),
        HCMD_NAME(STORED_BEACON_NTF),
 };