diff options
author | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-09-10 11:23:30 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-09-11 16:42:36 -0400 |
commit | 43d2a30fa80166243498fc6b8c841828ce52fcc1 (patch) | |
tree | 47e1db5f4cbb7a7f2c9bd058383fb29a51d4b04b | |
parent | 666a73f327d5a8fec58bbfedb36ae545862f479e (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/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.c | 88 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 22 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/hw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/testmode.c | 382 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/testmode.h | 46 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/testmode_i.h | 70 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 18 |
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 | ||
13 | ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o | 13 | ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o |
14 | ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o | ||
14 | ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o | 15 | ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o |
15 | 16 | ||
16 | obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o | 17 | obj-$(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 | ||
30 | unsigned int ath10k_debug_mask; | 31 | unsigned int ath10k_debug_mask; |
31 | static bool uart_print; | 32 | static 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 | ||
260 | static int ath10k_download_fw(struct ath10k *ar) | 261 | static 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 | ||
274 | exit: | ||
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 | ||
570 | static int ath10k_init_download_firmware(struct ath10k *ar) | 592 | static 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 | ||
693 | int ath10k_core_start(struct ath10k *ar) | 719 | int 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 | |||
338 | enum 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 | ||
335 | enum ath10k_fw_features { | 346 | enum 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); |
552 | void ath10k_core_destroy(struct ath10k *ar); | 572 | void ath10k_core_destroy(struct ath10k *ar); |
553 | 573 | ||
554 | int ath10k_core_start(struct ath10k *ar); | 574 | int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode); |
555 | int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); | 575 | int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); |
556 | void ath10k_core_stop(struct ath10k *ar); | 576 | void ath10k_core_stop(struct ath10k *ar); |
557 | int ath10k_core_register(struct ath10k *ar, u32 chip_id); | 577 | int 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 | } |
143 | EXPORT_SYMBOL(ath10k_print_driver_info); | 144 | EXPORT_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 | |||
29 | static 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 | */ | ||
41 | bool 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 | |||
104 | out: | ||
105 | spin_unlock_bh(&ar->data_lock); | ||
106 | |||
107 | return consumed; | ||
108 | } | ||
109 | |||
110 | static 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 | |||
142 | static 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 | |||
220 | err_power_down: | ||
221 | ath10k_hif_power_down(ar); | ||
222 | |||
223 | err_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 | |||
231 | err: | ||
232 | mutex_unlock(&ar->conf_mutex); | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | static 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 | |||
260 | static 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 | |||
279 | out: | ||
280 | mutex_unlock(&ar->conf_mutex); | ||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static 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 | |||
335 | out: | ||
336 | mutex_unlock(&ar->conf_mutex); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | int 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 | |||
369 | void 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 | |||
380 | out: | ||
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 | |||
21 | void ath10k_testmode_destroy(struct ath10k *ar); | ||
22 | |||
23 | bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb); | ||
24 | int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
25 | void *data, int len); | ||
26 | |||
27 | #else | ||
28 | |||
29 | static inline void ath10k_testmode_destroy(struct ath10k *ar) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | static inline bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, | ||
34 | struct sk_buff *skb) | ||
35 | { | ||
36 | return false; | ||
37 | } | ||
38 | |||
39 | static 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 | |||
29 | enum 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 | */ | ||
45 | enum 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 */ |
28 | static struct wmi_cmd_map wmi_cmd_map = { | 29 | static 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 | ||
2599 | out: | ||
2582 | dev_kfree_skb(skb); | 2600 | dev_kfree_skb(skb); |
2583 | } | 2601 | } |
2584 | 2602 | ||