Commit d3b4dc01 authored by Haim Dreyfuss's avatar Haim Dreyfuss Committed by Luca Coelho
Browse files

iwlwifi: mvm: add support for new version for D0I3_END_CMD



During D3 state there are some flows which requires FW reset.
Add new API to support it.

Signed-off-by: default avatarHaim Dreyfuss <haim.dreyfuss@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent ee4cce9b
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -64,6 +64,14 @@
#ifndef __iwl_fw_api_d3_h__
#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
+28 −1
Original line number Diff line number Diff line
@@ -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);
		}
	}

	/*
+4 −0
Original line number Diff line number Diff line
@@ -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];
+27 −0
Original line number Diff line number Diff line
@@ -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.