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