143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo/*
243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * Copyright (c) 2014 Qualcomm Atheros, Inc.
343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo *
443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * Permission to use, copy, modify, and/or distribute this software for any
543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * purpose with or without fee is hereby granted, provided that the above
643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * copyright notice and this permission notice appear in all copies.
743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo *
843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo */
1643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
1743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include "testmode.h"
1843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
1943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include <net/netlink.h>
2043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include <linux/firmware.h>
2143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
2243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include "debug.h"
2343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include "wmi.h"
2443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include "hif.h"
2543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include "hw.h"
2643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
2743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo#include "testmode_i.h"
2843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
2943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valostatic const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
3043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	[ATH10K_TM_ATTR_CMD]		= { .type = NLA_U32 },
3143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	[ATH10K_TM_ATTR_DATA]		= { .type = NLA_BINARY,
3243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo					    .len = ATH10K_TM_DATA_MAX_LEN },
3343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	[ATH10K_TM_ATTR_WMI_CMDID]	= { .type = NLA_U32 },
3443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	[ATH10K_TM_ATTR_VERSION_MAJOR]	= { .type = NLA_U32 },
3543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	[ATH10K_TM_ATTR_VERSION_MINOR]	= { .type = NLA_U32 },
3643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo};
3743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
3843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo/* Returns true if callee consumes the skb and the skb should be discarded.
3943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo * Returns false if skb is not used. Does not sleep.
4043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo */
4143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valobool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
4243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
4343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	struct sk_buff *nl_skb;
4443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	bool consumed;
4543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	int ret;
4643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
4743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
4843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		   "testmode event wmi cmd_id %d skb %p skb->len %d\n",
4943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		   cmd_id, skb, skb->len);
5043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
5143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
5243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
5343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	spin_lock_bh(&ar->data_lock);
5443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
5543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (!ar->testmode.utf_monitor) {
5643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		consumed = false;
5743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
5843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
5943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
6043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	/* Only testmode.c should be handling events from utf firmware,
6143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	 * otherwise all sort of problems will arise as mac80211 operations
6243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	 * are not initialised.
6343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	 */
6443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	consumed = true;
6543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
6643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
6743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo						   2 * sizeof(u32) + skb->len,
6843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo						   GFP_ATOMIC);
6943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (!nl_skb) {
7043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_warn(ar,
7143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    "failed to allocate skb for testmode wmi event\n");
7243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
7343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
7443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
7543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
7643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
7743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_warn(ar,
7843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    "failed to to put testmode wmi event cmd attribute: %d\n",
7943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    ret);
8043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		kfree_skb(nl_skb);
8143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
8243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
8343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
8443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
8543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
8643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_warn(ar,
8743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    "failed to to put testmode wmi even cmd_id: %d\n",
8843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    ret);
8943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		kfree_skb(nl_skb);
9043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
9143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
9243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
9343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
9443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
9543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_warn(ar,
9643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    "failed to copy skb to testmode wmi event: %d\n",
9743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    ret);
9843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		kfree_skb(nl_skb);
9943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
10043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
10143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
10243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
10343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
10443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoout:
10543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	spin_unlock_bh(&ar->data_lock);
10643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
10743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	return consumed;
10843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
10943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
11043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valostatic int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
11143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
11243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	struct sk_buff *skb;
11343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	int ret;
11443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
11543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
11643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		   "testmode cmd get version_major %d version_minor %d\n",
11743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		   ATH10K_TESTMODE_VERSION_MAJOR,
11843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		   ATH10K_TESTMODE_VERSION_MINOR);
11943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
12043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
12143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo						nla_total_size(sizeof(u32)));
12243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (!skb)
12343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return -ENOMEM;
12443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
12543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
12643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			  ATH10K_TESTMODE_VERSION_MAJOR);
12743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
12843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		kfree_skb(skb);
12943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return ret;
13043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
13143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
13243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
13343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			  ATH10K_TESTMODE_VERSION_MINOR);
13443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
13543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		kfree_skb(skb);
13643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return ret;
13743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
13843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
13943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	return cfg80211_testmode_reply(skb);
14043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
14143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
14243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valostatic int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
14343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
14443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	char filename[100];
14543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	int ret;
14643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
14743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
14843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
14943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_lock(&ar->conf_mutex);
15043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
15143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ar->state == ATH10K_STATE_UTF) {
15243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -EALREADY;
15343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto err;
15443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
15543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
15643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	/* start utf only when the driver is not in use  */
15743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ar->state != ATH10K_STATE_OFF) {
15843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -EBUSY;
15943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto err;
16043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
16143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
16243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (WARN_ON(ar->testmode.utf != NULL)) {
16343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		/* utf image is already downloaded, it shouldn't be */
16443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -EEXIST;
16543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto err;
16643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
16743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
16843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	snprintf(filename, sizeof(filename), "%s/%s",
16943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
17043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
17143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	/* load utf firmware image */
17243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
17343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
17443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
17543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    filename, ret);
17643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto err;
17743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
17843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
17943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	spin_lock_bh(&ar->data_lock);
18043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
18143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ar->testmode.utf_monitor = true;
18243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
18343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	spin_unlock_bh(&ar->data_lock);
18443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
18543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	BUILD_BUG_ON(sizeof(ar->fw_features) !=
18643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		     sizeof(ar->testmode.orig_fw_features));
18743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
18843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	memcpy(ar->testmode.orig_fw_features, ar->fw_features,
18943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	       sizeof(ar->fw_features));
19043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
19143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	/* utf.bin firmware image does not advertise firmware features. Do
19243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	 * an ugly hack where we force the firmware features so that wmi.c
19343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	 * will use the correct WMI interface.
19443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	 */
19543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	memset(ar->fw_features, 0, sizeof(ar->fw_features));
19643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	__set_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features);
19743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
19843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = ath10k_hif_power_up(ar);
19943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
20043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
20143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ar->state = ATH10K_STATE_OFF;
20243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto err_fw_features;
20343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
20443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
20543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF);
20643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
20743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
20843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ar->state = ATH10K_STATE_OFF;
20943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto err_power_down;
21043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
21143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
21243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ar->state = ATH10K_STATE_UTF;
21343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
21443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_info(ar, "UTF firmware started\n");
21543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
21643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_unlock(&ar->conf_mutex);
21743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
21843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	return 0;
21943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
22043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoerr_power_down:
22143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_hif_power_down(ar);
22243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
22343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoerr_fw_features:
22443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	/* return the original firmware features */
22543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	memcpy(ar->fw_features, ar->testmode.orig_fw_features,
22643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	       sizeof(ar->fw_features));
22743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
22843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	release_firmware(ar->testmode.utf);
22943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ar->testmode.utf = NULL;
23043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
23143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoerr:
23243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_unlock(&ar->conf_mutex);
23343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
23443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	return ret;
23543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
23643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
23743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valostatic void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
23843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
23943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	lockdep_assert_held(&ar->conf_mutex);
24043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
24143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_core_stop(ar);
24243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_hif_power_down(ar);
24343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
24443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	spin_lock_bh(&ar->data_lock);
24543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
24643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ar->testmode.utf_monitor = false;
24743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
24843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	spin_unlock_bh(&ar->data_lock);
24943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
25043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	/* return the original firmware features */
25143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	memcpy(ar->fw_features, ar->testmode.orig_fw_features,
25243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	       sizeof(ar->fw_features));
25343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
25443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	release_firmware(ar->testmode.utf);
25543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ar->testmode.utf = NULL;
25643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
25743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ar->state = ATH10K_STATE_OFF;
25843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
25943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
26043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valostatic int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
26143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
26243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	int ret;
26343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
26443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
26543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
26643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_lock(&ar->conf_mutex);
26743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
26843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ar->state != ATH10K_STATE_UTF) {
26943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -ENETDOWN;
27043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
27143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
27243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
27343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	__ath10k_tm_cmd_utf_stop(ar);
27443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
27543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = 0;
27643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
27743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_info(ar, "UTF firmware stopped\n");
27843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
27943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoout:
28043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_unlock(&ar->conf_mutex);
28143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	return ret;
28243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
28343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
28443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valostatic int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
28543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
28643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	struct sk_buff *skb;
28743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	int ret, buf_len;
28843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	u32 cmd_id;
28943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	void *buf;
29043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
29143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_lock(&ar->conf_mutex);
29243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
29343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ar->state != ATH10K_STATE_UTF) {
29443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -ENETDOWN;
29543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
29643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
29743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
29843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (!tb[ATH10K_TM_ATTR_DATA]) {
29943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -EINVAL;
30043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
30143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
30243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
30343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
30443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -EINVAL;
30543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
30643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
30743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
30843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
30943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
31043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
31143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
31243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
31343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		   "testmode cmd wmi cmd_id %d buf %p buf_len %d\n",
31443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		   cmd_id, buf, buf_len);
31543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
31643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
31743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
31843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	skb = ath10k_wmi_alloc_skb(ar, buf_len);
31943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (!skb) {
32043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ret = -ENOMEM;
32143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
32243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
32343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
32443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	memcpy(skb->data, buf, buf_len);
32543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
32643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
32743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret) {
32843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
32943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			    ret);
33043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
33143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
33243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
33343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = 0;
33443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
33543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoout:
33643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_unlock(&ar->conf_mutex);
33743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	return ret;
33843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
33943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
34043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoint ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
34143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		  void *data, int len)
34243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
34343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	struct ath10k *ar = hw->priv;
34443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
34543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	int ret;
34643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
34743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len,
34843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo			ath10k_tm_policy);
34943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ret)
35043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return ret;
35143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
35243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (!tb[ATH10K_TM_ATTR_CMD])
35343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return -EINVAL;
35443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
35543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
35643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	case ATH10K_TM_CMD_GET_VERSION:
35743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return ath10k_tm_cmd_get_version(ar, tb);
35843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	case ATH10K_TM_CMD_UTF_START:
35943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return ath10k_tm_cmd_utf_start(ar, tb);
36043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	case ATH10K_TM_CMD_UTF_STOP:
36143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return ath10k_tm_cmd_utf_stop(ar, tb);
36243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	case ATH10K_TM_CMD_WMI:
36343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return ath10k_tm_cmd_wmi(ar, tb);
36443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	default:
36543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		return -EOPNOTSUPP;
36643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
36743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
36843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
36943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valovoid ath10k_testmode_destroy(struct ath10k *ar)
37043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo{
37143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_lock(&ar->conf_mutex);
37243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
37343d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	if (ar->state != ATH10K_STATE_UTF) {
37443d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		/* utf firmware is not running, nothing to do */
37543d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo		goto out;
37643d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	}
37743d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
37843d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	__ath10k_tm_cmd_utf_stop(ar);
37943d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo
38043d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valoout:
38143d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo	mutex_unlock(&ar->conf_mutex);
38243d2a30fa80166243498fc6b8c841828ce52fcc1Kalle Valo}
383