aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKalle Valo <kvalo@qca.qualcomm.com>2014-09-10 11:23:30 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2014-09-11 16:42:36 -0400
commit43d2a30fa80166243498fc6b8c841828ce52fcc1 (patch)
tree47e1db5f4cbb7a7f2c9bd058383fb29a51d4b04b
parent666a73f327d5a8fec58bbfedb36ae545862f479e (diff)
ath10k: add testmode
Add testmode interface for starting and using UTF firmware which is used to run factory tests. This is implemented by adding new state ATH10K_STATE_UTF and user space can enable this state with ATH10K_TM_CMD_UTF_START command. To go back to normal mode user space can send ATH10K_TM_CMD_UTF_STOP. Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c88
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c5
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/testmode.c382
-rw-r--r--drivers/net/wireless/ath/ath10k/testmode.h46
-rw-r--r--drivers/net/wireless/ath/ath10k/testmode_i.h70
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c18
11 files changed, 614 insertions, 30 deletions
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 2cfb63ca9327..8b1b1adb477a 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -11,6 +11,7 @@ ath10k_core-y += mac.o \
11 bmi.o 11 bmi.o
12 12
13ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o 13ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
14ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
14ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o 15ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
15 16
16obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o 17obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index eadb22519912..cee18c89d7f2 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -26,6 +26,7 @@
26#include "bmi.h" 26#include "bmi.h"
27#include "debug.h" 27#include "debug.h"
28#include "htt.h" 28#include "htt.h"
29#include "testmode.h"
29 30
30unsigned int ath10k_debug_mask; 31unsigned int ath10k_debug_mask;
31static bool uart_print; 32static bool uart_print;
@@ -257,21 +258,42 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
257 return 0; 258 return 0;
258} 259}
259 260
260static int ath10k_download_fw(struct ath10k *ar) 261static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
261{ 262{
262 u32 address; 263 u32 address, data_len;
264 const char *mode_name;
265 const void *data;
263 int ret; 266 int ret;
264 267
265 address = ar->hw_params.patch_load_addr; 268 address = ar->hw_params.patch_load_addr;
266 269
267 ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data, 270 switch (mode) {
268 ar->firmware_len); 271 case ATH10K_FIRMWARE_MODE_NORMAL:
272 data = ar->firmware_data;
273 data_len = ar->firmware_len;
274 mode_name = "normal";
275 break;
276 case ATH10K_FIRMWARE_MODE_UTF:
277 data = ar->testmode.utf->data;
278 data_len = ar->testmode.utf->size;
279 mode_name = "utf";
280 break;
281 default:
282 ath10k_err(ar, "unknown firmware mode: %d\n", mode);
283 return -EINVAL;
284 }
285
286 ath10k_dbg(ar, ATH10K_DBG_BOOT,
287 "boot uploading firmware image %p len %d mode %s\n",
288 data, data_len, mode_name);
289
290 ret = ath10k_bmi_fast_download(ar, address, data, data_len);
269 if (ret) { 291 if (ret) {
270 ath10k_err(ar, "could not write fw (%d)\n", ret); 292 ath10k_err(ar, "failed to download %s firmware: %d\n",
271 goto exit; 293 mode_name, ret);
294 return ret;
272 } 295 }
273 296
274exit:
275 return ret; 297 return ret;
276} 298}
277 299
@@ -567,7 +589,8 @@ success:
567 return 0; 589 return 0;
568} 590}
569 591
570static int ath10k_init_download_firmware(struct ath10k *ar) 592static int ath10k_init_download_firmware(struct ath10k *ar,
593 enum ath10k_firmware_mode mode)
571{ 594{
572 int ret; 595 int ret;
573 596
@@ -583,7 +606,7 @@ static int ath10k_init_download_firmware(struct ath10k *ar)
583 return ret; 606 return ret;
584 } 607 }
585 608
586 ret = ath10k_download_fw(ar); 609 ret = ath10k_download_fw(ar, mode);
587 if (ret) { 610 if (ret) {
588 ath10k_err(ar, "failed to download firmware: %d\n", ret); 611 ath10k_err(ar, "failed to download firmware: %d\n", ret);
589 return ret; 612 return ret;
@@ -685,12 +708,15 @@ static void ath10k_core_restart(struct work_struct *work)
685 case ATH10K_STATE_WEDGED: 708 case ATH10K_STATE_WEDGED:
686 ath10k_warn(ar, "device is wedged, will not restart\n"); 709 ath10k_warn(ar, "device is wedged, will not restart\n");
687 break; 710 break;
711 case ATH10K_STATE_UTF:
712 ath10k_warn(ar, "firmware restart in UTF mode not supported\n");
713 break;
688 } 714 }
689 715
690 mutex_unlock(&ar->conf_mutex); 716 mutex_unlock(&ar->conf_mutex);
691} 717}
692 718
693int ath10k_core_start(struct ath10k *ar) 719int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
694{ 720{
695 int status; 721 int status;
696 722
@@ -703,7 +729,7 @@ int ath10k_core_start(struct ath10k *ar)
703 goto err; 729 goto err;
704 } 730 }
705 731
706 status = ath10k_init_download_firmware(ar); 732 status = ath10k_init_download_firmware(ar, mode);
707 if (status) 733 if (status)
708 goto err; 734 goto err;
709 735
@@ -760,10 +786,12 @@ int ath10k_core_start(struct ath10k *ar)
760 goto err_hif_stop; 786 goto err_hif_stop;
761 } 787 }
762 788
763 status = ath10k_htt_connect(&ar->htt); 789 if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
764 if (status) { 790 status = ath10k_htt_connect(&ar->htt);
765 ath10k_err(ar, "failed to connect htt (%d)\n", status); 791 if (status) {
766 goto err_hif_stop; 792 ath10k_err(ar, "failed to connect htt (%d)\n", status);
793 goto err_hif_stop;
794 }
767 } 795 }
768 796
769 status = ath10k_wmi_connect(ar); 797 status = ath10k_wmi_connect(ar);
@@ -778,11 +806,13 @@ int ath10k_core_start(struct ath10k *ar)
778 goto err_hif_stop; 806 goto err_hif_stop;
779 } 807 }
780 808
781 status = ath10k_wmi_wait_for_service_ready(ar); 809 if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
782 if (status <= 0) { 810 status = ath10k_wmi_wait_for_service_ready(ar);
783 ath10k_warn(ar, "wmi service ready event not received"); 811 if (status <= 0) {
784 status = -ETIMEDOUT; 812 ath10k_warn(ar, "wmi service ready event not received");
785 goto err_hif_stop; 813 status = -ETIMEDOUT;
814 goto err_hif_stop;
815 }
786 } 816 }
787 817
788 ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n", 818 ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
@@ -802,10 +832,13 @@ int ath10k_core_start(struct ath10k *ar)
802 goto err_hif_stop; 832 goto err_hif_stop;
803 } 833 }
804 834
805 status = ath10k_htt_setup(&ar->htt); 835 /* we don't care about HTT in UTF mode */
806 if (status) { 836 if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
807 ath10k_err(ar, "failed to setup htt: %d\n", status); 837 status = ath10k_htt_setup(&ar->htt);
808 goto err_hif_stop; 838 if (status) {
839 ath10k_err(ar, "failed to setup htt: %d\n", status);
840 goto err_hif_stop;
841 }
809 } 842 }
810 843
811 status = ath10k_debug_start(ar); 844 status = ath10k_debug_start(ar);
@@ -861,7 +894,8 @@ void ath10k_core_stop(struct ath10k *ar)
861 lockdep_assert_held(&ar->conf_mutex); 894 lockdep_assert_held(&ar->conf_mutex);
862 895
863 /* try to suspend target */ 896 /* try to suspend target */
864 if (ar->state != ATH10K_STATE_RESTARTING) 897 if (ar->state != ATH10K_STATE_RESTARTING &&
898 ar->state != ATH10K_STATE_UTF)
865 ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); 899 ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
866 900
867 ath10k_debug_stop(ar); 901 ath10k_debug_stop(ar);
@@ -914,7 +948,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
914 948
915 mutex_lock(&ar->conf_mutex); 949 mutex_lock(&ar->conf_mutex);
916 950
917 ret = ath10k_core_start(ar); 951 ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
918 if (ret) { 952 if (ret) {
919 ath10k_err(ar, "could not init core (%d)\n", ret); 953 ath10k_err(ar, "could not init core (%d)\n", ret);
920 ath10k_core_free_firmware_files(ar); 954 ath10k_core_free_firmware_files(ar);
@@ -1041,6 +1075,8 @@ void ath10k_core_unregister(struct ath10k *ar)
1041 * unhappy about callback failures. */ 1075 * unhappy about callback failures. */
1042 ath10k_mac_unregister(ar); 1076 ath10k_mac_unregister(ar);
1043 1077
1078 ath10k_testmode_destroy(ar);
1079
1044 ath10k_core_free_firmware_files(ar); 1080 ath10k_core_free_firmware_files(ar);
1045 1081
1046 ath10k_debug_unregister(ar); 1082 ath10k_debug_unregister(ar);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index a2695e33f29a..fe531ea6926c 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -330,6 +330,17 @@ enum ath10k_state {
330 * prevents completion timeouts and makes the driver more responsive to 330 * prevents completion timeouts and makes the driver more responsive to
331 * userspace commands. This is also prevents recursive recovery. */ 331 * userspace commands. This is also prevents recursive recovery. */
332 ATH10K_STATE_WEDGED, 332 ATH10K_STATE_WEDGED,
333
334 /* factory tests */
335 ATH10K_STATE_UTF,
336};
337
338enum ath10k_firmware_mode {
339 /* the default mode, standard 802.11 functionality */
340 ATH10K_FIRMWARE_MODE_NORMAL,
341
342 /* factory tests etc */
343 ATH10K_FIRMWARE_MODE_UTF,
333}; 344};
334 345
335enum ath10k_fw_features { 346enum ath10k_fw_features {
@@ -543,6 +554,15 @@ struct ath10k {
543 struct ath10k_spec_scan config; 554 struct ath10k_spec_scan config;
544 } spectral; 555 } spectral;
545 556
557 struct {
558 /* protected by conf_mutex */
559 const struct firmware *utf;
560 DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
561
562 /* protected by data_lock */
563 bool utf_monitor;
564 } testmode;
565
546 /* must be last */ 566 /* must be last */
547 u8 drv_priv[0] __aligned(sizeof(void *)); 567 u8 drv_priv[0] __aligned(sizeof(void *));
548}; 568};
@@ -551,7 +571,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
551 const struct ath10k_hif_ops *hif_ops); 571 const struct ath10k_hif_ops *hif_ops);
552void ath10k_core_destroy(struct ath10k *ar); 572void ath10k_core_destroy(struct ath10k *ar);
553 573
554int ath10k_core_start(struct ath10k *ar); 574int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode);
555int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); 575int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
556void ath10k_core_stop(struct ath10k *ar); 576void ath10k_core_stop(struct ath10k *ar);
557int ath10k_core_register(struct ath10k *ar, u32 chip_id); 577int ath10k_core_register(struct ath10k *ar, u32 chip_id);
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 97109221ffb3..f948a4d8ee59 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -134,11 +134,12 @@ void ath10k_print_driver_info(struct ath10k *ar)
134 ar->fw_api, 134 ar->fw_api,
135 ar->htt.target_version_major, 135 ar->htt.target_version_major,
136 ar->htt.target_version_minor); 136 ar->htt.target_version_minor);
137 ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d\n", 137 ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
138 config_enabled(CONFIG_ATH10K_DEBUG), 138 config_enabled(CONFIG_ATH10K_DEBUG),
139 config_enabled(CONFIG_ATH10K_DEBUGFS), 139 config_enabled(CONFIG_ATH10K_DEBUGFS),
140 config_enabled(CONFIG_ATH10K_TRACING), 140 config_enabled(CONFIG_ATH10K_TRACING),
141 config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)); 141 config_enabled(CONFIG_ATH10K_DFS_CERTIFIED),
142 config_enabled(CONFIG_NL80211_TESTMODE));
142} 143}
143EXPORT_SYMBOL(ath10k_print_driver_info); 144EXPORT_SYMBOL(ath10k_print_driver_info);
144 145
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 71c80842eea7..b3774f7f492c 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -34,6 +34,7 @@ enum ath10k_debug_mask {
34 ATH10K_DBG_DATA = 0x00000200, 34 ATH10K_DBG_DATA = 0x00000200,
35 ATH10K_DBG_BMI = 0x00000400, 35 ATH10K_DBG_BMI = 0x00000400,
36 ATH10K_DBG_REGULATORY = 0x00000800, 36 ATH10K_DBG_REGULATORY = 0x00000800,
37 ATH10K_DBG_TESTMODE = 0x00001000,
37 ATH10K_DBG_ANY = 0xffffffff, 38 ATH10K_DBG_ANY = 0xffffffff,
38}; 39};
39 40
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 13568b01de9f..3cf5702c1e7e 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -36,6 +36,8 @@
36#define ATH10K_FW_API2_FILE "firmware-2.bin" 36#define ATH10K_FW_API2_FILE "firmware-2.bin"
37#define ATH10K_FW_API3_FILE "firmware-3.bin" 37#define ATH10K_FW_API3_FILE "firmware-3.bin"
38 38
39#define ATH10K_FW_UTF_FILE "utf.bin"
40
39/* includes also the null byte */ 41/* includes also the null byte */
40#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" 42#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
41 43
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index f80eeed16cb6..5b35fff8127f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -26,6 +26,7 @@
26#include "wmi.h" 26#include "wmi.h"
27#include "htt.h" 27#include "htt.h"
28#include "txrx.h" 28#include "txrx.h"
29#include "testmode.h"
29 30
30/**********/ 31/**********/
31/* Crypto */ 32/* Crypto */
@@ -2480,6 +2481,9 @@ static int ath10k_start(struct ieee80211_hw *hw)
2480 WARN_ON(1); 2481 WARN_ON(1);
2481 ret = -EINVAL; 2482 ret = -EINVAL;
2482 goto err; 2483 goto err;
2484 case ATH10K_STATE_UTF:
2485 ret = -EBUSY;
2486 goto err;
2483 } 2487 }
2484 2488
2485 ret = ath10k_hif_power_up(ar); 2489 ret = ath10k_hif_power_up(ar);
@@ -2488,7 +2492,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
2488 goto err_off; 2492 goto err_off;
2489 } 2493 }
2490 2494
2491 ret = ath10k_core_start(ar); 2495 ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
2492 if (ret) { 2496 if (ret) {
2493 ath10k_err(ar, "Could not init core: %d\n", ret); 2497 ath10k_err(ar, "Could not init core: %d\n", ret);
2494 goto err_power_down; 2498 goto err_power_down;
@@ -4456,6 +4460,9 @@ static const struct ieee80211_ops ath10k_ops = {
4456 .sta_rc_update = ath10k_sta_rc_update, 4460 .sta_rc_update = ath10k_sta_rc_update,
4457 .get_tsf = ath10k_get_tsf, 4461 .get_tsf = ath10k_get_tsf,
4458 .ampdu_action = ath10k_ampdu_action, 4462 .ampdu_action = ath10k_ampdu_action,
4463
4464 CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
4465
4459#ifdef CONFIG_PM 4466#ifdef CONFIG_PM
4460 .suspend = ath10k_suspend, 4467 .suspend = ath10k_suspend,
4461 .resume = ath10k_resume, 4468 .resume = ath10k_resume,
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c
new file mode 100644
index 000000000000..483db9cb8c96
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -0,0 +1,382 @@
1/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "testmode.h"
18
19#include <net/netlink.h>
20#include <linux/firmware.h>
21
22#include "debug.h"
23#include "wmi.h"
24#include "hif.h"
25#include "hw.h"
26
27#include "testmode_i.h"
28
29static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
30 [ATH10K_TM_ATTR_CMD] = { .type = NLA_U32 },
31 [ATH10K_TM_ATTR_DATA] = { .type = NLA_BINARY,
32 .len = ATH10K_TM_DATA_MAX_LEN },
33 [ATH10K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },
34 [ATH10K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },
35 [ATH10K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
36};
37
38/* Returns true if callee consumes the skb and the skb should be discarded.
39 * Returns false if skb is not used. Does not sleep.
40 */
41bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
42{
43 struct sk_buff *nl_skb;
44 bool consumed;
45 int ret;
46
47 ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
48 "testmode event wmi cmd_id %d skb %p skb->len %d\n",
49 cmd_id, skb, skb->len);
50
51 ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
52
53 spin_lock_bh(&ar->data_lock);
54
55 if (!ar->testmode.utf_monitor) {
56 consumed = false;
57 goto out;
58 }
59
60 /* Only testmode.c should be handling events from utf firmware,
61 * otherwise all sort of problems will arise as mac80211 operations
62 * are not initialised.
63 */
64 consumed = true;
65
66 nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
67 2 * sizeof(u32) + skb->len,
68 GFP_ATOMIC);
69 if (!nl_skb) {
70 ath10k_warn(ar,
71 "failed to allocate skb for testmode wmi event\n");
72 goto out;
73 }
74
75 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
76 if (ret) {
77 ath10k_warn(ar,
78 "failed to to put testmode wmi event cmd attribute: %d\n",
79 ret);
80 kfree_skb(nl_skb);
81 goto out;
82 }
83
84 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
85 if (ret) {
86 ath10k_warn(ar,
87 "failed to to put testmode wmi even cmd_id: %d\n",
88 ret);
89 kfree_skb(nl_skb);
90 goto out;
91 }
92
93 ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
94 if (ret) {
95 ath10k_warn(ar,
96 "failed to copy skb to testmode wmi event: %d\n",
97 ret);
98 kfree_skb(nl_skb);
99 goto out;
100 }
101
102 cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
103
104out:
105 spin_unlock_bh(&ar->data_lock);
106
107 return consumed;
108}
109
110static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
111{
112 struct sk_buff *skb;
113 int ret;
114
115 ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
116 "testmode cmd get version_major %d version_minor %d\n",
117 ATH10K_TESTMODE_VERSION_MAJOR,
118 ATH10K_TESTMODE_VERSION_MINOR);
119
120 skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
121 nla_total_size(sizeof(u32)));
122 if (!skb)
123 return -ENOMEM;
124
125 ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
126 ATH10K_TESTMODE_VERSION_MAJOR);
127 if (ret) {
128 kfree_skb(skb);
129 return ret;
130 }
131
132 ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
133 ATH10K_TESTMODE_VERSION_MINOR);
134 if (ret) {
135 kfree_skb(skb);
136 return ret;
137 }
138
139 return cfg80211_testmode_reply(skb);
140}
141
142static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
143{
144 char filename[100];
145 int ret;
146
147 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
148
149 mutex_lock(&ar->conf_mutex);
150
151 if (ar->state == ATH10K_STATE_UTF) {
152 ret = -EALREADY;
153 goto err;
154 }
155
156 /* start utf only when the driver is not in use */
157 if (ar->state != ATH10K_STATE_OFF) {
158 ret = -EBUSY;
159 goto err;
160 }
161
162 if (WARN_ON(ar->testmode.utf != NULL)) {
163 /* utf image is already downloaded, it shouldn't be */
164 ret = -EEXIST;
165 goto err;
166 }
167
168 snprintf(filename, sizeof(filename), "%s/%s",
169 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
170
171 /* load utf firmware image */
172 ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
173 if (ret) {
174 ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
175 filename, ret);
176 goto err;
177 }
178
179 spin_lock_bh(&ar->data_lock);
180
181 ar->testmode.utf_monitor = true;
182
183 spin_unlock_bh(&ar->data_lock);
184
185 BUILD_BUG_ON(sizeof(ar->fw_features) !=
186 sizeof(ar->testmode.orig_fw_features));
187
188 memcpy(ar->testmode.orig_fw_features, ar->fw_features,
189 sizeof(ar->fw_features));
190
191 /* utf.bin firmware image does not advertise firmware features. Do
192 * an ugly hack where we force the firmware features so that wmi.c
193 * will use the correct WMI interface.
194 */
195 memset(ar->fw_features, 0, sizeof(ar->fw_features));
196 __set_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features);
197
198 ret = ath10k_hif_power_up(ar);
199 if (ret) {
200 ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
201 ar->state = ATH10K_STATE_OFF;
202 goto err_fw_features;
203 }
204
205 ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF);
206 if (ret) {
207 ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
208 ar->state = ATH10K_STATE_OFF;
209 goto err_power_down;
210 }
211
212 ar->state = ATH10K_STATE_UTF;
213
214 ath10k_info(ar, "UTF firmware started\n");
215
216 mutex_unlock(&ar->conf_mutex);
217
218 return 0;
219
220err_power_down:
221 ath10k_hif_power_down(ar);
222
223err_fw_features:
224 /* return the original firmware features */
225 memcpy(ar->fw_features, ar->testmode.orig_fw_features,
226 sizeof(ar->fw_features));
227
228 release_firmware(ar->testmode.utf);
229 ar->testmode.utf = NULL;
230
231err:
232 mutex_unlock(&ar->conf_mutex);
233
234 return ret;
235}
236
237static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
238{
239 lockdep_assert_held(&ar->conf_mutex);
240
241 ath10k_core_stop(ar);
242 ath10k_hif_power_down(ar);
243
244 spin_lock_bh(&ar->data_lock);
245
246 ar->testmode.utf_monitor = false;
247
248 spin_unlock_bh(&ar->data_lock);
249
250 /* return the original firmware features */
251 memcpy(ar->fw_features, ar->testmode.orig_fw_features,
252 sizeof(ar->fw_features));
253
254 release_firmware(ar->testmode.utf);
255 ar->testmode.utf = NULL;
256
257 ar->state = ATH10K_STATE_OFF;
258}
259
260static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
261{
262 int ret;
263
264 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
265
266 mutex_lock(&ar->conf_mutex);
267
268 if (ar->state != ATH10K_STATE_UTF) {
269 ret = -ENETDOWN;
270 goto out;
271 }
272
273 __ath10k_tm_cmd_utf_stop(ar);
274
275 ret = 0;
276
277 ath10k_info(ar, "UTF firmware stopped\n");
278
279out:
280 mutex_unlock(&ar->conf_mutex);
281 return ret;
282}
283
284static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
285{
286 struct sk_buff *skb;
287 int ret, buf_len;
288 u32 cmd_id;
289 void *buf;
290
291 mutex_lock(&ar->conf_mutex);
292
293 if (ar->state != ATH10K_STATE_UTF) {
294 ret = -ENETDOWN;
295 goto out;
296 }
297
298 if (!tb[ATH10K_TM_ATTR_DATA]) {
299 ret = -EINVAL;
300 goto out;
301 }
302
303 if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
304 ret = -EINVAL;
305 goto out;
306 }
307
308 buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
309 buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
310 cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
311
312 ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
313 "testmode cmd wmi cmd_id %d buf %p buf_len %d\n",
314 cmd_id, buf, buf_len);
315
316 ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
317
318 skb = ath10k_wmi_alloc_skb(ar, buf_len);
319 if (!skb) {
320 ret = -ENOMEM;
321 goto out;
322 }
323
324 memcpy(skb->data, buf, buf_len);
325
326 ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
327 if (ret) {
328 ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
329 ret);
330 goto out;
331 }
332
333 ret = 0;
334
335out:
336 mutex_unlock(&ar->conf_mutex);
337 return ret;
338}
339
340int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
341 void *data, int len)
342{
343 struct ath10k *ar = hw->priv;
344 struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
345 int ret;
346
347 ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len,
348 ath10k_tm_policy);
349 if (ret)
350 return ret;
351
352 if (!tb[ATH10K_TM_ATTR_CMD])
353 return -EINVAL;
354
355 switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
356 case ATH10K_TM_CMD_GET_VERSION:
357 return ath10k_tm_cmd_get_version(ar, tb);
358 case ATH10K_TM_CMD_UTF_START:
359 return ath10k_tm_cmd_utf_start(ar, tb);
360 case ATH10K_TM_CMD_UTF_STOP:
361 return ath10k_tm_cmd_utf_stop(ar, tb);
362 case ATH10K_TM_CMD_WMI:
363 return ath10k_tm_cmd_wmi(ar, tb);
364 default:
365 return -EOPNOTSUPP;
366 }
367}
368
369void ath10k_testmode_destroy(struct ath10k *ar)
370{
371 mutex_lock(&ar->conf_mutex);
372
373 if (ar->state != ATH10K_STATE_UTF) {
374 /* utf firmware is not running, nothing to do */
375 goto out;
376 }
377
378 __ath10k_tm_cmd_utf_stop(ar);
379
380out:
381 mutex_unlock(&ar->conf_mutex);
382}
diff --git a/drivers/net/wireless/ath/ath10k/testmode.h b/drivers/net/wireless/ath/ath10k/testmode.h
new file mode 100644
index 000000000000..9cdd150815db
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/testmode.h
@@ -0,0 +1,46 @@
1/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18
19#ifdef CONFIG_NL80211_TESTMODE
20
21void ath10k_testmode_destroy(struct ath10k *ar);
22
23bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb);
24int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
25 void *data, int len);
26
27#else
28
29static inline void ath10k_testmode_destroy(struct ath10k *ar)
30{
31}
32
33static inline bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id,
34 struct sk_buff *skb)
35{
36 return false;
37}
38
39static inline int ath10k_tm_cmd(struct ieee80211_hw *hw,
40 struct ieee80211_vif *vif,
41 void *data, int len)
42{
43 return 0;
44}
45
46#endif
diff --git a/drivers/net/wireless/ath/ath10k/testmode_i.h b/drivers/net/wireless/ath/ath10k/testmode_i.h
new file mode 100644
index 000000000000..ba81bf66ce85
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/testmode_i.h
@@ -0,0 +1,70 @@
1/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* "API" level of the ath10k testmode interface. Bump it after every
18 * incompatible interface change.
19 */
20#define ATH10K_TESTMODE_VERSION_MAJOR 1
21
22/* Bump this after every _compatible_ interface change, for example
23 * addition of a new command or an attribute.
24 */
25#define ATH10K_TESTMODE_VERSION_MINOR 0
26
27#define ATH10K_TM_DATA_MAX_LEN 5000
28
29enum ath10k_tm_attr {
30 __ATH10K_TM_ATTR_INVALID = 0,
31 ATH10K_TM_ATTR_CMD = 1,
32 ATH10K_TM_ATTR_DATA = 2,
33 ATH10K_TM_ATTR_WMI_CMDID = 3,
34 ATH10K_TM_ATTR_VERSION_MAJOR = 4,
35 ATH10K_TM_ATTR_VERSION_MINOR = 5,
36
37 /* keep last */
38 __ATH10K_TM_ATTR_AFTER_LAST,
39 ATH10K_TM_ATTR_MAX = __ATH10K_TM_ATTR_AFTER_LAST - 1,
40};
41
42/* All ath10k testmode interface commands specified in
43 * ATH10K_TM_ATTR_CMD
44 */
45enum ath10k_tm_cmd {
46 /* Returns the supported ath10k testmode interface version in
47 * ATH10K_TM_ATTR_VERSION. Always guaranteed to work. User space
48 * uses this to verify it's using the correct version of the
49 * testmode interface
50 */
51 ATH10K_TM_CMD_GET_VERSION = 0,
52
53 /* Boots the UTF firmware, the netdev interface must be down at the
54 * time.
55 */
56 ATH10K_TM_CMD_UTF_START = 1,
57
58 /* Shuts down the UTF firmware and puts the driver back into OFF
59 * state.
60 */
61 ATH10K_TM_CMD_UTF_STOP = 2,
62
63 /* The command used to transmit a WMI command to the firmware and
64 * the event to receive WMI events from the firmware. Without
65 * struct wmi_cmd_hdr header, only the WMI payload. Command id is
66 * provided with ATH10K_TM_ATTR_WMI_CMDID and payload in
67 * ATH10K_TM_ATTR_DATA.
68 */
69 ATH10K_TM_CMD_WMI = 3,
70};
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 67af370012f9..3e2213409074 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -23,6 +23,7 @@
23#include "debug.h" 23#include "debug.h"
24#include "wmi.h" 24#include "wmi.h"
25#include "mac.h" 25#include "mac.h"
26#include "testmode.h"
26 27
27/* MAIN WMI cmd track */ 28/* MAIN WMI cmd track */
28static struct wmi_cmd_map wmi_cmd_map = { 29static struct wmi_cmd_map wmi_cmd_map = {
@@ -2479,6 +2480,7 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
2479{ 2480{
2480 struct wmi_cmd_hdr *cmd_hdr; 2481 struct wmi_cmd_hdr *cmd_hdr;
2481 enum wmi_10x_event_id id; 2482 enum wmi_10x_event_id id;
2483 bool consumed;
2482 2484
2483 cmd_hdr = (struct wmi_cmd_hdr *)skb->data; 2485 cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
2484 id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); 2486 id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
@@ -2488,6 +2490,18 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
2488 2490
2489 trace_ath10k_wmi_event(ar, id, skb->data, skb->len); 2491 trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
2490 2492
2493 consumed = ath10k_tm_event_wmi(ar, id, skb);
2494
2495 /* Ready event must be handled normally also in UTF mode so that we
2496 * know the UTF firmware has booted, others we are just bypass WMI
2497 * events to testmode.
2498 */
2499 if (consumed && id != WMI_10X_READY_EVENTID) {
2500 ath10k_dbg(ar, ATH10K_DBG_WMI,
2501 "wmi testmode consumed 0x%x\n", id);
2502 goto out;
2503 }
2504
2491 switch (id) { 2505 switch (id) {
2492 case WMI_10X_MGMT_RX_EVENTID: 2506 case WMI_10X_MGMT_RX_EVENTID:
2493 ath10k_wmi_event_mgmt_rx(ar, skb); 2507 ath10k_wmi_event_mgmt_rx(ar, skb);
@@ -2574,11 +2588,15 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
2574 case WMI_10X_READY_EVENTID: 2588 case WMI_10X_READY_EVENTID:
2575 ath10k_wmi_ready_event_rx(ar, skb); 2589 ath10k_wmi_ready_event_rx(ar, skb);
2576 break; 2590 break;
2591 case WMI_10X_PDEV_UTF_EVENTID:
2592 /* ignore utf events */
2593 break;
2577 default: 2594 default:
2578 ath10k_warn(ar, "Unknown eventid: %d\n", id); 2595 ath10k_warn(ar, "Unknown eventid: %d\n", id);
2579 break; 2596 break;
2580 } 2597 }
2581 2598
2599out:
2582 dev_kfree_skb(skb); 2600 dev_kfree_skb(skb);
2583} 2601}
2584 2602