iwlwifi: mvm: add support for new version for D0I3_END_CMD
authorHaim Dreyfuss <haim.dreyfuss@intel.com>
Tue, 23 Jul 2019 15:27:45 +0000 (18:27 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 25 Oct 2019 07:10:05 +0000 (10:10 +0300)
During D3 state there are some flows which requires FW reset.
Add new API to support it.

Signed-off-by: Haim Dreyfuss <haim.dreyfuss@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@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/ops.c

index 4c3219e..3643b6b 100644 (file)
 #define __iwl_fw_api_d3_h__
 
 /**
+ * enum iwl_d0i3_flags - d0i3 flags
+ * @IWL_D0I3_RESET_REQUIRE: FW require reset upon resume
+ */
+enum iwl_d0i3_flags {
+       IWL_D0I3_RESET_REQUIRE = BIT(0),
+};
+
+/**
  * enum iwl_d3_wakeup_flags - D3 manager wakeup flags
  * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert
  */
index 86c2c58..1a9d83d 100644 (file)
@@ -1955,12 +1955,39 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        }
 
        if (d0i3_first) {
-               ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
+               struct iwl_host_cmd cmd = {
+                       .id = D0I3_END_CMD,
+                       .flags = CMD_WANT_SKB,
+               };
+               int len;
+
+               ret = iwl_mvm_send_cmd(mvm, &cmd);
                if (ret < 0) {
                        IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n",
                                ret);
                        goto err;
                }
+               switch (mvm->cmd_ver.d0i3_resp) {
+               case 0:
+                       break;
+               case 1:
+                       len = iwl_rx_packet_payload_len(cmd.resp_pkt);
+                       if (len != sizeof(u32)) {
+                               IWL_ERR(mvm,
+                                       "Error with D0I3_END_CMD response size (%d)\n",
+                                       len);
+                               goto err;
+                       }
+                       if (IWL_D0I3_RESET_REQUIRE &
+                           le32_to_cpu(*(__le32 *)cmd.resp_pkt->data)) {
+                               iwl_write32(mvm->trans, CSR_RESET,
+                                           CSR_RESET_REG_FLAG_FORCE_NMI);
+                               iwl_free_resp(&cmd);
+                       }
+                       break;
+               default:
+                       WARN_ON(1);
+               }
        }
 
        /*
index 843d00b..4325757 100644 (file)
@@ -1122,6 +1122,10 @@ struct iwl_mvm {
                int responses[IWL_MVM_TOF_MAX_APS];
        } ftm_initiator;
 
+       struct {
+               u8 d0i3_resp;
+       } cmd_ver;
+
        struct ieee80211_vif *nan_vif;
 #define IWL_MAX_BAID   32
        struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID];
index 3acbd5b..cc4b555 100644 (file)
@@ -608,6 +608,27 @@ static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = {
        .d3_debug_enable = iwl_mvm_d3_debug_enable,
 };
 
+static u8 iwl_mvm_lookup_notif_ver(struct iwl_mvm *mvm, u8 grp, u8 cmd, u8 def)
+{
+       const struct iwl_fw_cmd_version *entry;
+       unsigned int i;
+
+       if (!mvm->fw->ucode_capa.cmd_versions ||
+           !mvm->fw->ucode_capa.n_cmd_versions)
+               return def;
+
+       entry = mvm->fw->ucode_capa.cmd_versions;
+       for (i = 0; i < mvm->fw->ucode_capa.n_cmd_versions; i++, entry++) {
+               if (entry->group == grp && entry->cmd == cmd) {
+                       if (entry->notif_ver == IWL_FW_CMD_VER_UNKNOWN)
+                               return def;
+                       return entry->notif_ver;
+               }
+       }
+
+       return def;
+}
+
 static struct iwl_op_mode *
 iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                      const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -722,6 +743,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork);
 
+       mvm->cmd_ver.d0i3_resp =
+               iwl_mvm_lookup_notif_ver(mvm, LEGACY_GROUP, D0I3_END_CMD, 0);
+       /* we only support version 1 */
+       if (WARN_ON_ONCE(mvm->cmd_ver.d0i3_resp > 1))
+               goto out_free;
+
        /*
         * Populate the state variables that the transport layer needs
         * to know about.