diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-07-23 13:06:17 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-07-23 13:06:17 -0400 |
commit | d878b3af675da14917a249e33addb789d54d3094 (patch) | |
tree | 10c02a67e231993f74ab32bc0cdb51a74643b48e /drivers/net/wireless | |
parent | 16e754535a69152c12494da18eb3ea7947f5a434 (diff) | |
parent | f697267f827516fba4d0c325ed1db1e72f402f11 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Diffstat (limited to 'drivers/net/wireless')
21 files changed, 966 insertions, 395 deletions
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 7fd50428b934..6451d2b6abcf 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -20,16 +20,17 @@ config IWLWIFI | |||
20 | Intel 2000 Series Wi-Fi Adapters | 20 | Intel 2000 Series Wi-Fi Adapters |
21 | Intel 7260 Wi-Fi Adapter | 21 | Intel 7260 Wi-Fi Adapter |
22 | Intel 3160 Wi-Fi Adapter | 22 | Intel 3160 Wi-Fi Adapter |
23 | Intel 7265 Wi-Fi Adapter | ||
23 | 24 | ||
24 | 25 | ||
25 | This driver uses the kernel's mac80211 subsystem. | 26 | This driver uses the kernel's mac80211 subsystem. |
26 | 27 | ||
27 | In order to use this driver, you will need a microcode (uCode) | 28 | In order to use this driver, you will need a firmware |
28 | image for it. You can obtain the microcode from: | 29 | image for it. You can obtain the microcode from: |
29 | 30 | ||
30 | <http://intellinuxwireless.org/>. | 31 | <http://wireless.kernel.org/en/users/Drivers/iwlwifi>. |
31 | 32 | ||
32 | The microcode is typically installed in /lib/firmware. You can | 33 | The firmware is typically installed in /lib/firmware. You can |
33 | look in the hotplug script /etc/hotplug/firmware.agent to | 34 | look in the hotplug script /etc/hotplug/firmware.agent to |
34 | determine which directory FIRMWARE_DIR is set to when the script | 35 | determine which directory FIRMWARE_DIR is set to when the script |
35 | runs. | 36 | runs. |
@@ -39,9 +40,10 @@ config IWLWIFI | |||
39 | say M here and read <file:Documentation/kbuild/modules.txt>. The | 40 | say M here and read <file:Documentation/kbuild/modules.txt>. The |
40 | module will be called iwlwifi. | 41 | module will be called iwlwifi. |
41 | 42 | ||
43 | if IWLWIFI | ||
44 | |||
42 | config IWLWIFI_LEDS | 45 | config IWLWIFI_LEDS |
43 | bool | 46 | bool |
44 | depends on IWLWIFI | ||
45 | depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI | 47 | depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI |
46 | select LEDS_TRIGGERS | 48 | select LEDS_TRIGGERS |
47 | select MAC80211_LEDS | 49 | select MAC80211_LEDS |
@@ -49,7 +51,7 @@ config IWLWIFI_LEDS | |||
49 | 51 | ||
50 | config IWLDVM | 52 | config IWLDVM |
51 | tristate "Intel Wireless WiFi DVM Firmware support" | 53 | tristate "Intel Wireless WiFi DVM Firmware support" |
52 | depends on IWLWIFI | 54 | depends on m |
53 | default IWLWIFI | 55 | default IWLWIFI |
54 | help | 56 | help |
55 | This is the driver that supports the DVM firmware which is | 57 | This is the driver that supports the DVM firmware which is |
@@ -58,7 +60,7 @@ config IWLDVM | |||
58 | 60 | ||
59 | config IWLMVM | 61 | config IWLMVM |
60 | tristate "Intel Wireless WiFi MVM Firmware support" | 62 | tristate "Intel Wireless WiFi MVM Firmware support" |
61 | depends on IWLWIFI | 63 | depends on m |
62 | help | 64 | help |
63 | This is the driver that supports the MVM firmware which is | 65 | This is the driver that supports the MVM firmware which is |
64 | currently only available for 7260 and 3160 devices. | 66 | currently only available for 7260 and 3160 devices. |
@@ -70,7 +72,7 @@ config IWLWIFI_OPMODE_MODULAR | |||
70 | default y if IWLMVM=m | 72 | default y if IWLMVM=m |
71 | 73 | ||
72 | comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" | 74 | comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" |
73 | depends on IWLWIFI && IWLDVM=n && IWLMVM=n | 75 | depends on IWLDVM=n && IWLMVM=n |
74 | 76 | ||
75 | config IWLWIFI_BCAST_FILTERING | 77 | config IWLWIFI_BCAST_FILTERING |
76 | bool "Enable broadcast filtering" | 78 | bool "Enable broadcast filtering" |
@@ -86,11 +88,9 @@ config IWLWIFI_BCAST_FILTERING | |||
86 | expect incoming broadcasts for their normal operations. | 88 | expect incoming broadcasts for their normal operations. |
87 | 89 | ||
88 | menu "Debugging Options" | 90 | menu "Debugging Options" |
89 | depends on IWLWIFI | ||
90 | 91 | ||
91 | config IWLWIFI_DEBUG | 92 | config IWLWIFI_DEBUG |
92 | bool "Enable full debugging output in the iwlwifi driver" | 93 | bool "Enable full debugging output in the iwlwifi driver" |
93 | depends on IWLWIFI | ||
94 | ---help--- | 94 | ---help--- |
95 | This option will enable debug tracing output for the iwlwifi drivers | 95 | This option will enable debug tracing output for the iwlwifi drivers |
96 | 96 | ||
@@ -115,7 +115,7 @@ config IWLWIFI_DEBUG | |||
115 | 115 | ||
116 | config IWLWIFI_DEBUGFS | 116 | config IWLWIFI_DEBUGFS |
117 | bool "iwlwifi debugfs support" | 117 | bool "iwlwifi debugfs support" |
118 | depends on IWLWIFI && MAC80211_DEBUGFS | 118 | depends on MAC80211_DEBUGFS |
119 | ---help--- | 119 | ---help--- |
120 | Enable creation of debugfs files for the iwlwifi drivers. This | 120 | Enable creation of debugfs files for the iwlwifi drivers. This |
121 | is a low-impact option that allows getting insight into the | 121 | is a low-impact option that allows getting insight into the |
@@ -123,13 +123,12 @@ config IWLWIFI_DEBUGFS | |||
123 | 123 | ||
124 | config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE | 124 | config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE |
125 | bool "Experimental uCode support" | 125 | bool "Experimental uCode support" |
126 | depends on IWLWIFI && IWLWIFI_DEBUG | 126 | depends on IWLWIFI_DEBUG |
127 | ---help--- | 127 | ---help--- |
128 | Enable use of experimental ucode for testing and debugging. | 128 | Enable use of experimental ucode for testing and debugging. |
129 | 129 | ||
130 | config IWLWIFI_DEVICE_TRACING | 130 | config IWLWIFI_DEVICE_TRACING |
131 | bool "iwlwifi device access tracing" | 131 | bool "iwlwifi device access tracing" |
132 | depends on IWLWIFI | ||
133 | depends on EVENT_TRACING | 132 | depends on EVENT_TRACING |
134 | help | 133 | help |
135 | Say Y here to trace all commands, including TX frames and IO | 134 | Say Y here to trace all commands, including TX frames and IO |
@@ -145,3 +144,5 @@ config IWLWIFI_DEVICE_TRACING | |||
145 | If unsure, say Y so we can help you better when problems | 144 | If unsure, say Y so we can help you better when problems |
146 | occur. | 145 | occur. |
147 | endmenu | 146 | endmenu |
147 | |||
148 | endif | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 51486cc9d943..44b19e015102 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c | |||
@@ -85,6 +85,9 @@ | |||
85 | #define NVM_HW_SECTION_NUM_FAMILY_8000 10 | 85 | #define NVM_HW_SECTION_NUM_FAMILY_8000 10 |
86 | #define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" | 86 | #define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" |
87 | 87 | ||
88 | /* Max SDIO RX aggregation size of the ADDBA request/response */ | ||
89 | #define MAX_RX_AGG_SIZE_8260_SDIO 28 | ||
90 | |||
88 | static const struct iwl_base_params iwl8000_base_params = { | 91 | static const struct iwl_base_params iwl8000_base_params = { |
89 | .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, | 92 | .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, |
90 | .num_of_queues = IWLAGN_NUM_QUEUES, | 93 | .num_of_queues = IWLAGN_NUM_QUEUES, |
@@ -129,6 +132,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { | |||
129 | .nvm_ver = IWL8000_NVM_VERSION, | 132 | .nvm_ver = IWL8000_NVM_VERSION, |
130 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | 133 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, |
131 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, | 134 | .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, |
135 | .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, | ||
132 | }; | 136 | }; |
133 | 137 | ||
134 | MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); | 138 | MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 034c2fc4b69f..8da596db9abe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
@@ -240,6 +240,7 @@ struct iwl_pwr_tx_backoff { | |||
240 | * @d0i3: device uses d0i3 instead of d3 | 240 | * @d0i3: device uses d0i3 instead of d3 |
241 | * @nvm_hw_section_num: the ID of the HW NVM section | 241 | * @nvm_hw_section_num: the ID of the HW NVM section |
242 | * @pwr_tx_backoffs: translation table between power limits and backoffs | 242 | * @pwr_tx_backoffs: translation table between power limits and backoffs |
243 | * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response | ||
243 | * | 244 | * |
244 | * We enable the driver to be backward compatible wrt. hardware features. | 245 | * We enable the driver to be backward compatible wrt. hardware features. |
245 | * API differences in uCode shouldn't be handled here but through TLVs | 246 | * API differences in uCode shouldn't be handled here but through TLVs |
@@ -276,6 +277,7 @@ struct iwl_cfg { | |||
276 | const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; | 277 | const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; |
277 | bool no_power_up_nic_in_init; | 278 | bool no_power_up_nic_in_init; |
278 | const char *default_nvm_file; | 279 | const char *default_nvm_file; |
280 | unsigned int max_rx_agg_size; | ||
279 | }; | 281 | }; |
280 | 282 | ||
281 | /* | 283 | /* |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index c39a0b899e83..de5994a776c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | |||
@@ -70,21 +70,24 @@ | |||
70 | /** | 70 | /** |
71 | * enum iwl_fw_error_dump_type - types of data in the dump file | 71 | * enum iwl_fw_error_dump_type - types of data in the dump file |
72 | * @IWL_FW_ERROR_DUMP_SRAM: | 72 | * @IWL_FW_ERROR_DUMP_SRAM: |
73 | * @IWL_FW_ERROR_DUMP_REG: | 73 | * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 |
74 | * @IWL_FW_ERROR_DUMP_RXF: | 74 | * @IWL_FW_ERROR_DUMP_RXF: |
75 | * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as | 75 | * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as |
76 | * &struct iwl_fw_error_dump_txcmd packets | 76 | * &struct iwl_fw_error_dump_txcmd packets |
77 | * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info | 77 | * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info |
78 | * info on the device / firmware. | 78 | * info on the device / firmware. |
79 | * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor | 79 | * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor |
80 | * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several | ||
81 | * sections like this in a single file. | ||
80 | */ | 82 | */ |
81 | enum iwl_fw_error_dump_type { | 83 | enum iwl_fw_error_dump_type { |
82 | IWL_FW_ERROR_DUMP_SRAM = 0, | 84 | IWL_FW_ERROR_DUMP_SRAM = 0, |
83 | IWL_FW_ERROR_DUMP_REG = 1, | 85 | IWL_FW_ERROR_DUMP_CSR = 1, |
84 | IWL_FW_ERROR_DUMP_RXF = 2, | 86 | IWL_FW_ERROR_DUMP_RXF = 2, |
85 | IWL_FW_ERROR_DUMP_TXCMD = 3, | 87 | IWL_FW_ERROR_DUMP_TXCMD = 3, |
86 | IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, | 88 | IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, |
87 | IWL_FW_ERROR_DUMP_FW_MONITOR = 5, | 89 | IWL_FW_ERROR_DUMP_FW_MONITOR = 5, |
90 | IWL_FW_ERROR_DUMP_PRPH = 6, | ||
88 | 91 | ||
89 | IWL_FW_ERROR_DUMP_MAX, | 92 | IWL_FW_ERROR_DUMP_MAX, |
90 | }; | 93 | }; |
@@ -163,6 +166,16 @@ struct iwl_fw_error_dump_fw_mon { | |||
163 | } __packed; | 166 | } __packed; |
164 | 167 | ||
165 | /** | 168 | /** |
169 | * struct iwl_fw_error_dump_prph - periphery registers data | ||
170 | * @prph_start: address of the first register in this chunk | ||
171 | * @data: the content of the registers | ||
172 | */ | ||
173 | struct iwl_fw_error_dump_prph { | ||
174 | __le32 prph_start; | ||
175 | __le32 data[]; | ||
176 | }; | ||
177 | |||
178 | /** | ||
166 | * iwl_fw_error_next_data - advance fw error dump data pointer | 179 | * iwl_fw_error_next_data - advance fw error dump data pointer |
167 | * @data: previous data block | 180 | * @data: previous data block |
168 | * Returns: next data block | 181 | * Returns: next data block |
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index f2d39cb011fc..71507cf490e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -99,7 +99,7 @@ enum iwl_disable_11n { | |||
99 | * @wd_disable: disable stuck queue check, default = 1 | 99 | * @wd_disable: disable stuck queue check, default = 1 |
100 | * @bt_coex_active: enable bt coex, default = true | 100 | * @bt_coex_active: enable bt coex, default = true |
101 | * @led_mode: system default, default = 0 | 101 | * @led_mode: system default, default = 0 |
102 | * @power_save: disable power save, default = false | 102 | * @power_save: enable power save, default = false |
103 | * @power_level: power level, default = 1 | 103 | * @power_level: power level, default = 1 |
104 | * @debug_level: levels are IWL_DL_* | 104 | * @debug_level: levels are IWL_DL_* |
105 | * @ant_coupling: antenna coupling in dB, default = 0 | 105 | * @ant_coupling: antenna coupling in dB, default = 0 |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 34d49e171fb4..656371a668da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -394,6 +394,11 @@ struct iwl_trans_config { | |||
394 | const char *const *command_names; | 394 | const char *const *command_names; |
395 | }; | 395 | }; |
396 | 396 | ||
397 | struct iwl_trans_dump_data { | ||
398 | u32 len; | ||
399 | u8 data[]; | ||
400 | }; | ||
401 | |||
397 | struct iwl_trans; | 402 | struct iwl_trans; |
398 | 403 | ||
399 | /** | 404 | /** |
@@ -461,10 +466,8 @@ struct iwl_trans; | |||
461 | * @unref: release a reference previously taken with @ref. Note that | 466 | * @unref: release a reference previously taken with @ref. Note that |
462 | * initially the reference count is 1, making an initial @unref | 467 | * initially the reference count is 1, making an initial @unref |
463 | * necessary to allow low power states. | 468 | * necessary to allow low power states. |
464 | * @dump_data: fill a data dump with debug data, maybe containing last | 469 | * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last |
465 | * TX'ed commands and similar. When called with a NULL buffer and | 470 | * TX'ed commands and similar. The buffer will be vfree'd by the caller. |
466 | * zero buffer length, provide only the (estimated) required buffer | ||
467 | * length. Return the used buffer length. | ||
468 | * Note that the transport must fill in the proper file headers. | 471 | * Note that the transport must fill in the proper file headers. |
469 | */ | 472 | */ |
470 | struct iwl_trans_ops { | 473 | struct iwl_trans_ops { |
@@ -518,7 +521,7 @@ struct iwl_trans_ops { | |||
518 | void (*unref)(struct iwl_trans *trans); | 521 | void (*unref)(struct iwl_trans *trans); |
519 | 522 | ||
520 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 523 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
521 | u32 (*dump_data)(struct iwl_trans *trans, void *buf, u32 buflen); | 524 | struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); |
522 | #endif | 525 | #endif |
523 | }; | 526 | }; |
524 | 527 | ||
@@ -685,12 +688,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) | |||
685 | } | 688 | } |
686 | 689 | ||
687 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 690 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
688 | static inline u32 iwl_trans_dump_data(struct iwl_trans *trans, | 691 | static inline struct iwl_trans_dump_data * |
689 | void *buf, u32 buflen) | 692 | iwl_trans_dump_data(struct iwl_trans *trans) |
690 | { | 693 | { |
691 | if (!trans->ops->dump_data) | 694 | if (!trans->ops->dump_data) |
692 | return 0; | 695 | return NULL; |
693 | return trans->ops->dump_data(trans, buf, buflen); | 696 | return trans->ops->dump_data(trans); |
694 | } | 697 | } |
695 | #endif | 698 | #endif |
696 | 699 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 8110fe00bf55..2291bbcaaeab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c | |||
@@ -72,16 +72,56 @@ | |||
72 | 72 | ||
73 | #define BT_ANTENNA_COUPLING_THRESHOLD (30) | 73 | #define BT_ANTENNA_COUPLING_THRESHOLD (30) |
74 | 74 | ||
75 | const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = { | 75 | const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { |
76 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, | 76 | [BT_KILL_MSK_DEFAULT] = 0xfffffc00, |
77 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | 77 | [BT_KILL_MSK_NEVER] = 0xffffffff, |
78 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | 78 | [BT_KILL_MSK_ALWAYS] = 0, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = { | 81 | const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { |
82 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, | 82 | { |
83 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | 83 | BT_KILL_MSK_ALWAYS, |
84 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | 84 | BT_KILL_MSK_ALWAYS, |
85 | BT_KILL_MSK_ALWAYS, | ||
86 | }, | ||
87 | { | ||
88 | BT_KILL_MSK_NEVER, | ||
89 | BT_KILL_MSK_NEVER, | ||
90 | BT_KILL_MSK_NEVER, | ||
91 | }, | ||
92 | { | ||
93 | BT_KILL_MSK_NEVER, | ||
94 | BT_KILL_MSK_NEVER, | ||
95 | BT_KILL_MSK_NEVER, | ||
96 | }, | ||
97 | { | ||
98 | BT_KILL_MSK_DEFAULT, | ||
99 | BT_KILL_MSK_NEVER, | ||
100 | BT_KILL_MSK_DEFAULT, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { | ||
105 | { | ||
106 | BT_KILL_MSK_ALWAYS, | ||
107 | BT_KILL_MSK_ALWAYS, | ||
108 | BT_KILL_MSK_ALWAYS, | ||
109 | }, | ||
110 | { | ||
111 | BT_KILL_MSK_ALWAYS, | ||
112 | BT_KILL_MSK_ALWAYS, | ||
113 | BT_KILL_MSK_ALWAYS, | ||
114 | }, | ||
115 | { | ||
116 | BT_KILL_MSK_ALWAYS, | ||
117 | BT_KILL_MSK_ALWAYS, | ||
118 | BT_KILL_MSK_ALWAYS, | ||
119 | }, | ||
120 | { | ||
121 | BT_KILL_MSK_DEFAULT, | ||
122 | BT_KILL_MSK_ALWAYS, | ||
123 | BT_KILL_MSK_DEFAULT, | ||
124 | }, | ||
85 | }; | 125 | }; |
86 | 126 | ||
87 | static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { | 127 | static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { |
@@ -611,54 +651,43 @@ send_cmd: | |||
611 | return ret; | 651 | return ret; |
612 | } | 652 | } |
613 | 653 | ||
614 | static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm, | 654 | static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm) |
615 | bool reduced_tx_power) | ||
616 | { | 655 | { |
617 | enum iwl_bt_kill_msk bt_kill_msk; | ||
618 | struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; | ||
619 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; | 656 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; |
657 | u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); | ||
658 | u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut); | ||
659 | u32 ag = le32_to_cpu(notif->bt_activity_grading); | ||
660 | struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; | ||
661 | u8 ack_kill_msk[NUM_PHY_CTX] = {}; | ||
662 | u8 cts_kill_msk[NUM_PHY_CTX] = {}; | ||
663 | int i; | ||
620 | 664 | ||
621 | lockdep_assert_held(&mvm->mutex); | 665 | lockdep_assert_held(&mvm->mutex); |
622 | 666 | ||
623 | if (reduced_tx_power) { | 667 | ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut]; |
624 | /* Reduced Tx power has precedence on the type of the profile */ | 668 | cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut]; |
625 | bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; | ||
626 | } else { | ||
627 | /* Low latency BT profile is active: give higher prio to BT */ | ||
628 | if (BT_MBOX_MSG(notif, 3, SCO_STATE) || | ||
629 | BT_MBOX_MSG(notif, 3, A2DP_STATE) || | ||
630 | BT_MBOX_MSG(notif, 3, SNIFF_STATE)) | ||
631 | bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; | ||
632 | else | ||
633 | bt_kill_msk = BT_KILL_MSK_DEFAULT; | ||
634 | } | ||
635 | 669 | ||
636 | IWL_DEBUG_COEX(mvm, | 670 | ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut]; |
637 | "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", | 671 | cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut]; |
638 | bt_kill_msk, | ||
639 | BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", | ||
640 | BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", | ||
641 | BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); | ||
642 | 672 | ||
643 | /* Don't send HCMD if there is no update */ | 673 | /* Don't send HCMD if there is no update */ |
644 | if (bt_kill_msk == mvm->bt_kill_msk) | 674 | if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) || |
675 | !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk))) | ||
645 | return 0; | 676 | return 0; |
646 | 677 | ||
647 | mvm->bt_kill_msk = bt_kill_msk; | 678 | memcpy(mvm->bt_ack_kill_msk, ack_kill_msk, |
679 | sizeof(mvm->bt_ack_kill_msk)); | ||
680 | memcpy(mvm->bt_cts_kill_msk, cts_kill_msk, | ||
681 | sizeof(mvm->bt_cts_kill_msk)); | ||
648 | 682 | ||
649 | cmd.boost_values[0].kill_ack_msk = | 683 | BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values)); |
650 | cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | ||
651 | cmd.boost_values[0].kill_cts_msk = | ||
652 | cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
653 | 684 | ||
654 | cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk; | 685 | for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) { |
655 | cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk; | 686 | cmd.boost_values[i].kill_ack_msk = |
656 | cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk; | 687 | cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]); |
657 | cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk; | 688 | cmd.boost_values[i].kill_cts_msk = |
658 | 689 | cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]); | |
659 | IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", | 690 | } |
660 | iwl_bt_ack_kill_msk[bt_kill_msk], | ||
661 | iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
662 | 691 | ||
663 | return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0, | 692 | return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0, |
664 | sizeof(cmd), &cmd); | 693 | sizeof(cmd), &cmd); |
@@ -700,8 +729,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | |||
700 | struct iwl_bt_iterator_data { | 729 | struct iwl_bt_iterator_data { |
701 | struct iwl_bt_coex_profile_notif *notif; | 730 | struct iwl_bt_coex_profile_notif *notif; |
702 | struct iwl_mvm *mvm; | 731 | struct iwl_mvm *mvm; |
703 | u32 num_bss_ifaces; | ||
704 | bool reduced_tx_power; | ||
705 | struct ieee80211_chanctx_conf *primary; | 732 | struct ieee80211_chanctx_conf *primary; |
706 | struct ieee80211_chanctx_conf *secondary; | 733 | struct ieee80211_chanctx_conf *secondary; |
707 | bool primary_ll; | 734 | bool primary_ll; |
@@ -737,22 +764,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
737 | 764 | ||
738 | switch (vif->type) { | 765 | switch (vif->type) { |
739 | case NL80211_IFTYPE_STATION: | 766 | case NL80211_IFTYPE_STATION: |
740 | /* Count BSSes vifs */ | ||
741 | data->num_bss_ifaces++; | ||
742 | /* default smps_mode for BSS / P2P client is AUTOMATIC */ | 767 | /* default smps_mode for BSS / P2P client is AUTOMATIC */ |
743 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 768 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
744 | break; | 769 | break; |
745 | case NL80211_IFTYPE_AP: | 770 | case NL80211_IFTYPE_AP: |
746 | /* default smps_mode for AP / GO is OFF */ | 771 | if (!mvmvif->ap_ibss_active) |
747 | smps_mode = IEEE80211_SMPS_OFF; | ||
748 | if (!mvmvif->ap_ibss_active) { | ||
749 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
750 | smps_mode); | ||
751 | return; | 772 | return; |
752 | } | ||
753 | |||
754 | /* the Ack / Cts kill mask must be default if AP / GO */ | ||
755 | data->reduced_tx_power = false; | ||
756 | break; | 773 | break; |
757 | default: | 774 | default: |
758 | return; | 775 | return; |
@@ -763,11 +780,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
763 | /* If channel context is invalid or not on 2.4GHz .. */ | 780 | /* If channel context is invalid or not on 2.4GHz .. */ |
764 | if ((!chanctx_conf || | 781 | if ((!chanctx_conf || |
765 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { | 782 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { |
766 | /* ... relax constraints and disable rssi events */ | ||
767 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
768 | smps_mode); | ||
769 | data->reduced_tx_power = false; | ||
770 | if (vif->type == NL80211_IFTYPE_STATION) { | 783 | if (vif->type == NL80211_IFTYPE_STATION) { |
784 | /* ... relax constraints and disable rssi events */ | ||
785 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
786 | smps_mode); | ||
771 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, | 787 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, |
772 | false); | 788 | false); |
773 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | 789 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); |
@@ -779,9 +795,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
779 | if (bt_activity_grading >= BT_HIGH_TRAFFIC) | 795 | if (bt_activity_grading >= BT_HIGH_TRAFFIC) |
780 | smps_mode = IEEE80211_SMPS_STATIC; | 796 | smps_mode = IEEE80211_SMPS_STATIC; |
781 | else if (bt_activity_grading >= BT_LOW_TRAFFIC) | 797 | else if (bt_activity_grading >= BT_LOW_TRAFFIC) |
782 | smps_mode = vif->type == NL80211_IFTYPE_AP ? | 798 | smps_mode = IEEE80211_SMPS_DYNAMIC; |
783 | IEEE80211_SMPS_OFF : | ||
784 | IEEE80211_SMPS_DYNAMIC; | ||
785 | 799 | ||
786 | /* relax SMPS contraints for next association */ | 800 | /* relax SMPS contraints for next association */ |
787 | if (!vif->bss_conf.assoc) | 801 | if (!vif->bss_conf.assoc) |
@@ -795,7 +809,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
795 | "mac %d: bt_activity_grading %d smps_req %d\n", | 809 | "mac %d: bt_activity_grading %d smps_req %d\n", |
796 | mvmvif->id, bt_activity_grading, smps_mode); | 810 | mvmvif->id, bt_activity_grading, smps_mode); |
797 | 811 | ||
798 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); | 812 | if (vif->type == NL80211_IFTYPE_STATION) |
813 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
814 | smps_mode); | ||
799 | 815 | ||
800 | /* low latency is always primary */ | 816 | /* low latency is always primary */ |
801 | if (iwl_mvm_vif_low_latency(mvmvif)) { | 817 | if (iwl_mvm_vif_low_latency(mvmvif)) { |
@@ -846,7 +862,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
846 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || | 862 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || |
847 | mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || | 863 | mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || |
848 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { | 864 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { |
849 | data->reduced_tx_power = false; | ||
850 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); | 865 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); |
851 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | 866 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); |
852 | return; | 867 | return; |
@@ -861,23 +876,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
861 | if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { | 876 | if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { |
862 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) | 877 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) |
863 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | 878 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); |
864 | |||
865 | /* | ||
866 | * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the | ||
867 | * BSS / P2P clients have rssi above threshold. | ||
868 | * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before | ||
869 | * the iteration, if one interface's rssi isn't good enough, | ||
870 | * bt_kill_msk will be set to default values. | ||
871 | */ | ||
872 | } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { | 879 | } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { |
873 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) | 880 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) |
874 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | 881 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); |
875 | |||
876 | /* | ||
877 | * One interface hasn't rssi above threshold, bt_kill_msk must | ||
878 | * be set to default values. | ||
879 | */ | ||
880 | data->reduced_tx_power = false; | ||
881 | } | 882 | } |
882 | 883 | ||
883 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ | 884 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ |
@@ -889,7 +890,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | |||
889 | struct iwl_bt_iterator_data data = { | 890 | struct iwl_bt_iterator_data data = { |
890 | .mvm = mvm, | 891 | .mvm = mvm, |
891 | .notif = &mvm->last_bt_notif, | 892 | .notif = &mvm->last_bt_notif, |
892 | .reduced_tx_power = true, | ||
893 | }; | 893 | }; |
894 | struct iwl_bt_coex_ci_cmd cmd = {}; | 894 | struct iwl_bt_coex_ci_cmd cmd = {}; |
895 | u8 ci_bw_idx; | 895 | u8 ci_bw_idx; |
@@ -959,14 +959,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | |||
959 | memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); | 959 | memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); |
960 | } | 960 | } |
961 | 961 | ||
962 | /* | 962 | if (iwl_mvm_bt_udpate_sw_boost(mvm)) |
963 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
964 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
965 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
966 | */ | ||
967 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
968 | |||
969 | if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power)) | ||
970 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | 963 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); |
971 | } | 964 | } |
972 | 965 | ||
@@ -1035,16 +1028,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | |||
1035 | return; | 1028 | return; |
1036 | 1029 | ||
1037 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1030 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1038 | |||
1039 | data->num_bss_ifaces++; | ||
1040 | |||
1041 | /* | ||
1042 | * This interface doesn't support reduced Tx power (because of low | ||
1043 | * RSSI probably), then set bt_kill_msk to default values. | ||
1044 | */ | ||
1045 | if (!mvmsta->bt_reduced_txpower) | ||
1046 | data->reduced_tx_power = false; | ||
1047 | /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ | ||
1048 | } | 1031 | } |
1049 | 1032 | ||
1050 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1033 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
@@ -1053,7 +1036,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1053 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | 1036 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; |
1054 | struct iwl_bt_iterator_data data = { | 1037 | struct iwl_bt_iterator_data data = { |
1055 | .mvm = mvm, | 1038 | .mvm = mvm, |
1056 | .reduced_tx_power = true, | ||
1057 | }; | 1039 | }; |
1058 | int ret; | 1040 | int ret; |
1059 | 1041 | ||
@@ -1100,14 +1082,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1100 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 1082 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
1101 | iwl_mvm_bt_rssi_iterator, &data); | 1083 | iwl_mvm_bt_rssi_iterator, &data); |
1102 | 1084 | ||
1103 | /* | 1085 | if (iwl_mvm_bt_udpate_sw_boost(mvm)) |
1104 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
1105 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
1106 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
1107 | */ | ||
1108 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
1109 | |||
1110 | if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power)) | ||
1111 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | 1086 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); |
1112 | } | 1087 | } |
1113 | 1088 | ||
@@ -1150,7 +1125,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | |||
1150 | enum iwl_bt_coex_lut_type lut_type; | 1125 | enum iwl_bt_coex_lut_type lut_type; |
1151 | 1126 | ||
1152 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) | 1127 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) |
1153 | return iwl_mvm_coex_agg_time_limit_old(mvm, sta); | 1128 | return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta); |
1154 | 1129 | ||
1155 | if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) | 1130 | if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) |
1156 | return true; | 1131 | return true; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index ce50363d314b..a3be33359927 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | |||
@@ -649,10 +649,6 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
649 | sizeof(iwl_bt_prio_boost)); | 649 | sizeof(iwl_bt_prio_boost)); |
650 | memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, | 650 | memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, |
651 | sizeof(iwl_bt_mprio_lut)); | 651 | sizeof(iwl_bt_mprio_lut)); |
652 | bt_cmd->kill_ack_msk = | ||
653 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); | ||
654 | bt_cmd->kill_cts_msk = | ||
655 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); | ||
656 | 652 | ||
657 | send_cmd: | 653 | send_cmd: |
658 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); | 654 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); |
@@ -664,12 +660,13 @@ send_cmd: | |||
664 | return ret; | 660 | return ret; |
665 | } | 661 | } |
666 | 662 | ||
667 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | 663 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm) |
668 | bool reduced_tx_power) | ||
669 | { | 664 | { |
670 | enum iwl_bt_kill_msk bt_kill_msk; | ||
671 | struct iwl_bt_coex_cmd_old *bt_cmd; | ||
672 | struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old; | 665 | struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old; |
666 | u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); | ||
667 | u32 ag = le32_to_cpu(notif->bt_activity_grading); | ||
668 | struct iwl_bt_coex_cmd_old *bt_cmd; | ||
669 | u8 ack_kill_msk, cts_kill_msk; | ||
673 | struct iwl_host_cmd cmd = { | 670 | struct iwl_host_cmd cmd = { |
674 | .id = BT_CONFIG, | 671 | .id = BT_CONFIG, |
675 | .data[0] = &bt_cmd, | 672 | .data[0] = &bt_cmd, |
@@ -680,31 +677,15 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | |||
680 | 677 | ||
681 | lockdep_assert_held(&mvm->mutex); | 678 | lockdep_assert_held(&mvm->mutex); |
682 | 679 | ||
683 | if (reduced_tx_power) { | 680 | ack_kill_msk = iwl_bt_ack_kill_msk[ag][primary_lut]; |
684 | /* Reduced Tx power has precedence on the type of the profile */ | 681 | cts_kill_msk = iwl_bt_cts_kill_msk[ag][primary_lut]; |
685 | bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; | ||
686 | } else { | ||
687 | /* Low latency BT profile is active: give higher prio to BT */ | ||
688 | if (BT_MBOX_MSG(notif, 3, SCO_STATE) || | ||
689 | BT_MBOX_MSG(notif, 3, A2DP_STATE) || | ||
690 | BT_MBOX_MSG(notif, 3, SNIFF_STATE)) | ||
691 | bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; | ||
692 | else | ||
693 | bt_kill_msk = BT_KILL_MSK_DEFAULT; | ||
694 | } | ||
695 | |||
696 | IWL_DEBUG_COEX(mvm, | ||
697 | "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", | ||
698 | bt_kill_msk, | ||
699 | BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", | ||
700 | BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", | ||
701 | BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); | ||
702 | 682 | ||
703 | /* Don't send HCMD if there is no update */ | 683 | if (mvm->bt_ack_kill_msk[0] == ack_kill_msk && |
704 | if (bt_kill_msk == mvm->bt_kill_msk) | 684 | mvm->bt_cts_kill_msk[0] == cts_kill_msk) |
705 | return 0; | 685 | return 0; |
706 | 686 | ||
707 | mvm->bt_kill_msk = bt_kill_msk; | 687 | mvm->bt_ack_kill_msk[0] = ack_kill_msk; |
688 | mvm->bt_cts_kill_msk[0] = cts_kill_msk; | ||
708 | 689 | ||
709 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | 690 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); |
710 | if (!bt_cmd) | 691 | if (!bt_cmd) |
@@ -712,16 +693,12 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | |||
712 | cmd.data[0] = bt_cmd; | 693 | cmd.data[0] = bt_cmd; |
713 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); | 694 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); |
714 | 695 | ||
715 | bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | 696 | bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk]); |
716 | bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | 697 | bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk]); |
717 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | | 698 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | |
718 | BT_VALID_KILL_ACK | | 699 | BT_VALID_KILL_ACK | |
719 | BT_VALID_KILL_CTS); | 700 | BT_VALID_KILL_CTS); |
720 | 701 | ||
721 | IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", | ||
722 | iwl_bt_ack_kill_msk[bt_kill_msk], | ||
723 | iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
724 | |||
725 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 702 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
726 | 703 | ||
727 | kfree(bt_cmd); | 704 | kfree(bt_cmd); |
@@ -777,8 +754,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | |||
777 | struct iwl_bt_iterator_data { | 754 | struct iwl_bt_iterator_data { |
778 | struct iwl_bt_coex_profile_notif_old *notif; | 755 | struct iwl_bt_coex_profile_notif_old *notif; |
779 | struct iwl_mvm *mvm; | 756 | struct iwl_mvm *mvm; |
780 | u32 num_bss_ifaces; | ||
781 | bool reduced_tx_power; | ||
782 | struct ieee80211_chanctx_conf *primary; | 757 | struct ieee80211_chanctx_conf *primary; |
783 | struct ieee80211_chanctx_conf *secondary; | 758 | struct ieee80211_chanctx_conf *secondary; |
784 | bool primary_ll; | 759 | bool primary_ll; |
@@ -814,22 +789,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
814 | 789 | ||
815 | switch (vif->type) { | 790 | switch (vif->type) { |
816 | case NL80211_IFTYPE_STATION: | 791 | case NL80211_IFTYPE_STATION: |
817 | /* Count BSSes vifs */ | ||
818 | data->num_bss_ifaces++; | ||
819 | /* default smps_mode for BSS / P2P client is AUTOMATIC */ | 792 | /* default smps_mode for BSS / P2P client is AUTOMATIC */ |
820 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 793 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
821 | break; | 794 | break; |
822 | case NL80211_IFTYPE_AP: | 795 | case NL80211_IFTYPE_AP: |
823 | /* default smps_mode for AP / GO is OFF */ | 796 | if (!mvmvif->ap_ibss_active) |
824 | smps_mode = IEEE80211_SMPS_OFF; | ||
825 | if (!mvmvif->ap_ibss_active) { | ||
826 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
827 | smps_mode); | ||
828 | return; | 797 | return; |
829 | } | ||
830 | |||
831 | /* the Ack / Cts kill mask must be default if AP / GO */ | ||
832 | data->reduced_tx_power = false; | ||
833 | break; | 798 | break; |
834 | default: | 799 | default: |
835 | return; | 800 | return; |
@@ -840,11 +805,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
840 | /* If channel context is invalid or not on 2.4GHz .. */ | 805 | /* If channel context is invalid or not on 2.4GHz .. */ |
841 | if ((!chanctx_conf || | 806 | if ((!chanctx_conf || |
842 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { | 807 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { |
843 | /* ... relax constraints and disable rssi events */ | ||
844 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
845 | smps_mode); | ||
846 | data->reduced_tx_power = false; | ||
847 | if (vif->type == NL80211_IFTYPE_STATION) { | 808 | if (vif->type == NL80211_IFTYPE_STATION) { |
809 | /* ... relax constraints and disable rssi events */ | ||
810 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
811 | smps_mode); | ||
848 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, | 812 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, |
849 | false); | 813 | false); |
850 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | 814 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); |
@@ -869,7 +833,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
869 | mvmvif->id, data->notif->bt_status, bt_activity_grading, | 833 | mvmvif->id, data->notif->bt_status, bt_activity_grading, |
870 | smps_mode); | 834 | smps_mode); |
871 | 835 | ||
872 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); | 836 | if (vif->type == NL80211_IFTYPE_STATION) |
837 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
838 | smps_mode); | ||
873 | 839 | ||
874 | /* low latency is always primary */ | 840 | /* low latency is always primary */ |
875 | if (iwl_mvm_vif_low_latency(mvmvif)) { | 841 | if (iwl_mvm_vif_low_latency(mvmvif)) { |
@@ -920,7 +886,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
920 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || | 886 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || |
921 | mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || | 887 | mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || |
922 | !data->notif->bt_status) { | 888 | !data->notif->bt_status) { |
923 | data->reduced_tx_power = false; | ||
924 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); | 889 | iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); |
925 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | 890 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); |
926 | return; | 891 | return; |
@@ -935,23 +900,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
935 | if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { | 900 | if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { |
936 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) | 901 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) |
937 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | 902 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); |
938 | |||
939 | /* | ||
940 | * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the | ||
941 | * BSS / P2P clients have rssi above threshold. | ||
942 | * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before | ||
943 | * the iteration, if one interface's rssi isn't good enough, | ||
944 | * bt_kill_msk will be set to default values. | ||
945 | */ | ||
946 | } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { | 903 | } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { |
947 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) | 904 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) |
948 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | 905 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); |
949 | |||
950 | /* | ||
951 | * One interface hasn't rssi above threshold, bt_kill_msk must | ||
952 | * be set to default values. | ||
953 | */ | ||
954 | data->reduced_tx_power = false; | ||
955 | } | 906 | } |
956 | 907 | ||
957 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ | 908 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ |
@@ -963,7 +914,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | |||
963 | struct iwl_bt_iterator_data data = { | 914 | struct iwl_bt_iterator_data data = { |
964 | .mvm = mvm, | 915 | .mvm = mvm, |
965 | .notif = &mvm->last_bt_notif_old, | 916 | .notif = &mvm->last_bt_notif_old, |
966 | .reduced_tx_power = true, | ||
967 | }; | 917 | }; |
968 | struct iwl_bt_coex_ci_cmd_old cmd = {}; | 918 | struct iwl_bt_coex_ci_cmd_old cmd = {}; |
969 | u8 ci_bw_idx; | 919 | u8 ci_bw_idx; |
@@ -1037,14 +987,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | |||
1037 | memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd)); | 987 | memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd)); |
1038 | } | 988 | } |
1039 | 989 | ||
1040 | /* | 990 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm)) |
1041 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
1042 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
1043 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
1044 | */ | ||
1045 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
1046 | |||
1047 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) | ||
1048 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | 991 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); |
1049 | } | 992 | } |
1050 | 993 | ||
@@ -1115,16 +1058,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | |||
1115 | return; | 1058 | return; |
1116 | 1059 | ||
1117 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1060 | mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1118 | |||
1119 | data->num_bss_ifaces++; | ||
1120 | |||
1121 | /* | ||
1122 | * This interface doesn't support reduced Tx power (because of low | ||
1123 | * RSSI probably), then set bt_kill_msk to default values. | ||
1124 | */ | ||
1125 | if (!mvmsta->bt_reduced_txpower) | ||
1126 | data->reduced_tx_power = false; | ||
1127 | /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ | ||
1128 | } | 1061 | } |
1129 | 1062 | ||
1130 | void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1063 | void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
@@ -1133,7 +1066,6 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1133 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | 1066 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; |
1134 | struct iwl_bt_iterator_data data = { | 1067 | struct iwl_bt_iterator_data data = { |
1135 | .mvm = mvm, | 1068 | .mvm = mvm, |
1136 | .reduced_tx_power = true, | ||
1137 | }; | 1069 | }; |
1138 | int ret; | 1070 | int ret; |
1139 | 1071 | ||
@@ -1175,14 +1107,7 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1175 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 1107 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
1176 | iwl_mvm_bt_rssi_iterator, &data); | 1108 | iwl_mvm_bt_rssi_iterator, &data); |
1177 | 1109 | ||
1178 | /* | 1110 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm)) |
1179 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
1180 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
1181 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
1182 | */ | ||
1183 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
1184 | |||
1185 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) | ||
1186 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | 1111 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); |
1187 | } | 1112 | } |
1188 | 1113 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index f131ef0ec5b3..7d18f466fbb3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -146,17 +146,47 @@ static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, | |||
146 | char __user *user_buf, | 146 | char __user *user_buf, |
147 | size_t count, loff_t *ppos) | 147 | size_t count, loff_t *ppos) |
148 | { | 148 | { |
149 | struct iwl_fw_error_dump_file *dump_file = file->private_data; | 149 | struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; |
150 | ssize_t bytes_read = 0; | ||
151 | ssize_t bytes_read_trans = 0; | ||
152 | |||
153 | if (*ppos < dump_ptrs->op_mode_len) | ||
154 | bytes_read += | ||
155 | simple_read_from_buffer(user_buf, count, ppos, | ||
156 | dump_ptrs->op_mode_ptr, | ||
157 | dump_ptrs->op_mode_len); | ||
158 | |||
159 | if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len) | ||
160 | return bytes_read; | ||
161 | |||
162 | if (dump_ptrs->trans_ptr) { | ||
163 | *ppos -= dump_ptrs->op_mode_len; | ||
164 | bytes_read_trans = | ||
165 | simple_read_from_buffer(user_buf + bytes_read, | ||
166 | count - bytes_read, ppos, | ||
167 | dump_ptrs->trans_ptr->data, | ||
168 | dump_ptrs->trans_ptr->len); | ||
169 | *ppos += dump_ptrs->op_mode_len; | ||
170 | |||
171 | if (bytes_read_trans >= 0) | ||
172 | bytes_read += bytes_read_trans; | ||
173 | else if (!bytes_read) | ||
174 | /* propagate the failure */ | ||
175 | return bytes_read_trans; | ||
176 | } | ||
177 | |||
178 | return bytes_read; | ||
150 | 179 | ||
151 | return simple_read_from_buffer(user_buf, count, ppos, | ||
152 | dump_file, | ||
153 | le32_to_cpu(dump_file->file_len)); | ||
154 | } | 180 | } |
155 | 181 | ||
156 | static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, | 182 | static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, |
157 | struct file *file) | 183 | struct file *file) |
158 | { | 184 | { |
159 | vfree(file->private_data); | 185 | struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; |
186 | |||
187 | vfree(dump_ptrs->op_mode_ptr); | ||
188 | vfree(dump_ptrs->trans_ptr); | ||
189 | kfree(dump_ptrs); | ||
160 | 190 | ||
161 | return 0; | 191 | return 0; |
162 | } | 192 | } |
@@ -514,9 +544,9 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, | |||
514 | 544 | ||
515 | pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); | 545 | pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); |
516 | pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", | 546 | pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", |
517 | iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); | 547 | iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); |
518 | pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", | 548 | pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", |
519 | iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); | 549 | iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); |
520 | 550 | ||
521 | } else { | 551 | } else { |
522 | struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; | 552 | struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; |
@@ -531,10 +561,19 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, | |||
531 | le64_to_cpu(cmd->bt_secondary_ci)); | 561 | le64_to_cpu(cmd->bt_secondary_ci)); |
532 | 562 | ||
533 | pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); | 563 | pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); |
534 | pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", | 564 | pos += scnprintf(buf+pos, bufsz-pos, |
535 | iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); | 565 | "\tPrimary: ACK Kill Mask 0x%08x\n", |
536 | pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", | 566 | iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); |
537 | iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); | 567 | pos += scnprintf(buf+pos, bufsz-pos, |
568 | "\tPrimary: CTS Kill Mask 0x%08x\n", | ||
569 | iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); | ||
570 | pos += scnprintf(buf+pos, bufsz-pos, | ||
571 | "\tSecondary: ACK Kill Mask 0x%08x\n", | ||
572 | iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]); | ||
573 | pos += scnprintf(buf+pos, bufsz-pos, | ||
574 | "\tSecondary: CTS Kill Mask 0x%08x\n", | ||
575 | iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]); | ||
576 | |||
538 | } | 577 | } |
539 | 578 | ||
540 | mutex_unlock(&mvm->mutex); | 579 | mutex_unlock(&mvm->mutex); |
@@ -830,8 +869,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, | |||
830 | static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, | 869 | static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, |
831 | size_t count, loff_t *ppos) | 870 | size_t count, loff_t *ppos) |
832 | { | 871 | { |
872 | int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); | ||
873 | if (ret) | ||
874 | return ret; | ||
875 | |||
833 | iwl_force_nmi(mvm->trans); | 876 | iwl_force_nmi(mvm->trans); |
834 | 877 | ||
878 | iwl_mvm_unref(mvm, IWL_MVM_REF_NMI); | ||
879 | |||
835 | return count; | 880 | return count; |
836 | } | 881 | } |
837 | 882 | ||
@@ -1115,11 +1160,11 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, | |||
1115 | } | 1160 | } |
1116 | #endif | 1161 | #endif |
1117 | 1162 | ||
1118 | #define PRINT_MVM_REF(ref) do { \ | 1163 | #define PRINT_MVM_REF(ref) do { \ |
1119 | if (test_bit(ref, mvm->ref_bitmap)) \ | 1164 | if (mvm->refs[ref]) \ |
1120 | pos += scnprintf(buf + pos, bufsz - pos, \ | 1165 | pos += scnprintf(buf + pos, bufsz - pos, \ |
1121 | "\t(0x%lx) %s\n", \ | 1166 | "\t(0x%lx): %d %s\n", \ |
1122 | BIT(ref), #ref); \ | 1167 | BIT(ref), mvm->refs[ref], #ref); \ |
1123 | } while (0) | 1168 | } while (0) |
1124 | 1169 | ||
1125 | static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, | 1170 | static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, |
@@ -1127,12 +1172,17 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, | |||
1127 | size_t count, loff_t *ppos) | 1172 | size_t count, loff_t *ppos) |
1128 | { | 1173 | { |
1129 | struct iwl_mvm *mvm = file->private_data; | 1174 | struct iwl_mvm *mvm = file->private_data; |
1130 | int pos = 0; | 1175 | int i, pos = 0; |
1131 | char buf[256]; | 1176 | char buf[256]; |
1132 | const size_t bufsz = sizeof(buf); | 1177 | const size_t bufsz = sizeof(buf); |
1178 | u32 refs = 0; | ||
1133 | 1179 | ||
1134 | pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n", | 1180 | for (i = 0; i < IWL_MVM_REF_COUNT; i++) |
1135 | mvm->ref_bitmap[0]); | 1181 | if (mvm->refs[i]) |
1182 | refs |= BIT(i); | ||
1183 | |||
1184 | pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n", | ||
1185 | refs); | ||
1136 | 1186 | ||
1137 | PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); | 1187 | PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); |
1138 | PRINT_MVM_REF(IWL_MVM_REF_SCAN); | 1188 | PRINT_MVM_REF(IWL_MVM_REF_SCAN); |
@@ -1158,7 +1208,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, | |||
1158 | 1208 | ||
1159 | mutex_lock(&mvm->mutex); | 1209 | mutex_lock(&mvm->mutex); |
1160 | 1210 | ||
1161 | taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap); | 1211 | taken = mvm->refs[IWL_MVM_REF_USER]; |
1162 | if (value == 1 && !taken) | 1212 | if (value == 1 && !taken) |
1163 | iwl_mvm_ref(mvm, IWL_MVM_REF_USER); | 1213 | iwl_mvm_ref(mvm, IWL_MVM_REF_USER); |
1164 | else if (value == 0 && taken) | 1214 | else if (value == 0 && taken) |
@@ -1194,14 +1244,21 @@ iwl_dbgfs_prph_reg_read(struct file *file, | |||
1194 | int pos = 0; | 1244 | int pos = 0; |
1195 | char buf[32]; | 1245 | char buf[32]; |
1196 | const size_t bufsz = sizeof(buf); | 1246 | const size_t bufsz = sizeof(buf); |
1247 | int ret; | ||
1197 | 1248 | ||
1198 | if (!mvm->dbgfs_prph_reg_addr) | 1249 | if (!mvm->dbgfs_prph_reg_addr) |
1199 | return -EINVAL; | 1250 | return -EINVAL; |
1200 | 1251 | ||
1252 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ); | ||
1253 | if (ret) | ||
1254 | return ret; | ||
1255 | |||
1201 | pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", | 1256 | pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", |
1202 | mvm->dbgfs_prph_reg_addr, | 1257 | mvm->dbgfs_prph_reg_addr, |
1203 | iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); | 1258 | iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); |
1204 | 1259 | ||
1260 | iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ); | ||
1261 | |||
1205 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1262 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
1206 | } | 1263 | } |
1207 | 1264 | ||
@@ -1211,6 +1268,7 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, | |||
1211 | { | 1268 | { |
1212 | u8 args; | 1269 | u8 args; |
1213 | u32 value; | 1270 | u32 value; |
1271 | int ret; | ||
1214 | 1272 | ||
1215 | args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); | 1273 | args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); |
1216 | /* if we only want to set the reg address - nothing more to do */ | 1274 | /* if we only want to set the reg address - nothing more to do */ |
@@ -1221,7 +1279,13 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, | |||
1221 | if (args != 2) | 1279 | if (args != 2) |
1222 | return -EINVAL; | 1280 | return -EINVAL; |
1223 | 1281 | ||
1282 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); | ||
1283 | if (ret) | ||
1284 | return ret; | ||
1285 | |||
1224 | iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); | 1286 | iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); |
1287 | |||
1288 | iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); | ||
1225 | out: | 1289 | out: |
1226 | return count; | 1290 | return count; |
1227 | } | 1291 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index ab12aaa43034..69875716dcdb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | |||
@@ -385,6 +385,8 @@ enum iwl_bt_activity_grading { | |||
385 | BT_ON_NO_CONNECTION = 1, | 385 | BT_ON_NO_CONNECTION = 1, |
386 | BT_LOW_TRAFFIC = 2, | 386 | BT_LOW_TRAFFIC = 2, |
387 | BT_HIGH_TRAFFIC = 3, | 387 | BT_HIGH_TRAFFIC = 3, |
388 | |||
389 | BT_MAX_AG, | ||
388 | }; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */ | 390 | }; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */ |
389 | 391 | ||
390 | enum iwl_bt_ci_compliance { | 392 | enum iwl_bt_ci_compliance { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index b8e4e78d601b..95f5b3274efb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -133,6 +133,7 @@ enum { | |||
133 | /* Scan offload */ | 133 | /* Scan offload */ |
134 | SCAN_OFFLOAD_REQUEST_CMD = 0x51, | 134 | SCAN_OFFLOAD_REQUEST_CMD = 0x51, |
135 | SCAN_OFFLOAD_ABORT_CMD = 0x52, | 135 | SCAN_OFFLOAD_ABORT_CMD = 0x52, |
136 | HOT_SPOT_CMD = 0x53, | ||
136 | SCAN_OFFLOAD_COMPLETE = 0x6D, | 137 | SCAN_OFFLOAD_COMPLETE = 0x6D, |
137 | SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, | 138 | SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, |
138 | SCAN_OFFLOAD_CONFIG_CMD = 0x6f, | 139 | SCAN_OFFLOAD_CONFIG_CMD = 0x6f, |
@@ -910,6 +911,72 @@ struct iwl_phy_context_cmd { | |||
910 | __le32 dsp_cfg_flags; | 911 | __le32 dsp_cfg_flags; |
911 | } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ | 912 | } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ |
912 | 913 | ||
914 | /* | ||
915 | * Aux ROC command | ||
916 | * | ||
917 | * Command requests the firmware to create a time event for a certain duration | ||
918 | * and remain on the given channel. This is done by using the Aux framework in | ||
919 | * the FW. | ||
920 | * The command was first used for Hot Spot issues - but can be used regardless | ||
921 | * to Hot Spot. | ||
922 | * | ||
923 | * ( HOT_SPOT_CMD 0x53 ) | ||
924 | * | ||
925 | * @id_and_color: ID and color of the MAC | ||
926 | * @action: action to perform, one of FW_CTXT_ACTION_* | ||
927 | * @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the | ||
928 | * event_unique_id should be the id of the time event assigned by ucode. | ||
929 | * Otherwise ignore the event_unique_id. | ||
930 | * @sta_id_and_color: station id and color, resumed during "Remain On Channel" | ||
931 | * activity. | ||
932 | * @channel_info: channel info | ||
933 | * @node_addr: Our MAC Address | ||
934 | * @reserved: reserved for alignment | ||
935 | * @apply_time: GP2 value to start (should always be the current GP2 value) | ||
936 | * @apply_time_max_delay: Maximum apply time delay value in TU. Defines max | ||
937 | * time by which start of the event is allowed to be postponed. | ||
938 | * @duration: event duration in TU To calculate event duration: | ||
939 | * timeEventDuration = min(duration, remainingQuota) | ||
940 | */ | ||
941 | struct iwl_hs20_roc_req { | ||
942 | /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ | ||
943 | __le32 id_and_color; | ||
944 | __le32 action; | ||
945 | __le32 event_unique_id; | ||
946 | __le32 sta_id_and_color; | ||
947 | struct iwl_fw_channel_info channel_info; | ||
948 | u8 node_addr[ETH_ALEN]; | ||
949 | __le16 reserved; | ||
950 | __le32 apply_time; | ||
951 | __le32 apply_time_max_delay; | ||
952 | __le32 duration; | ||
953 | } __packed; /* HOT_SPOT_CMD_API_S_VER_1 */ | ||
954 | |||
955 | /* | ||
956 | * values for AUX ROC result values | ||
957 | */ | ||
958 | enum iwl_mvm_hot_spot { | ||
959 | HOT_SPOT_RSP_STATUS_OK, | ||
960 | HOT_SPOT_RSP_STATUS_TOO_MANY_EVENTS, | ||
961 | HOT_SPOT_MAX_NUM_OF_SESSIONS, | ||
962 | }; | ||
963 | |||
964 | /* | ||
965 | * Aux ROC command response | ||
966 | * | ||
967 | * In response to iwl_hs20_roc_req the FW sends this command to notify the | ||
968 | * driver the uid of the timevent. | ||
969 | * | ||
970 | * ( HOT_SPOT_CMD 0x53 ) | ||
971 | * | ||
972 | * @event_unique_id: Unique ID of time event assigned by ucode | ||
973 | * @status: Return status 0 is success, all the rest used for specific errors | ||
974 | */ | ||
975 | struct iwl_hs20_roc_res { | ||
976 | __le32 event_unique_id; | ||
977 | __le32 status; | ||
978 | } __packed; /* HOT_SPOT_RSP_API_S_VER_1 */ | ||
979 | |||
913 | #define IWL_RX_INFO_PHY_CNT 8 | 980 | #define IWL_RX_INFO_PHY_CNT 8 |
914 | #define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1 | 981 | #define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1 |
915 | #define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff | 982 | #define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 96b9cf8137e7..0e523e28cabf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -1074,8 +1074,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, | |||
1074 | /* Fill the common data for all mac context types */ | 1074 | /* Fill the common data for all mac context types */ |
1075 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 1075 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
1076 | 1076 | ||
1077 | /* Also enable probe requests to pass */ | 1077 | /* |
1078 | cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); | 1078 | * pass probe requests and beacons from other APs (needed |
1079 | * for ht protection) | ||
1080 | */ | ||
1081 | cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST | | ||
1082 | MAC_FILTER_IN_BEACON); | ||
1079 | 1083 | ||
1080 | /* Fill the data specific for ap mode */ | 1084 | /* Fill the data specific for ap mode */ |
1081 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap, | 1085 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap, |
@@ -1096,6 +1100,13 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, | |||
1096 | /* Fill the common data for all mac context types */ | 1100 | /* Fill the common data for all mac context types */ |
1097 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 1101 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
1098 | 1102 | ||
1103 | /* | ||
1104 | * pass probe requests and beacons from other APs (needed | ||
1105 | * for ht protection) | ||
1106 | */ | ||
1107 | cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST | | ||
1108 | MAC_FILTER_IN_BEACON); | ||
1109 | |||
1099 | /* Fill the data specific for GO mode */ | 1110 | /* Fill the data specific for GO mode */ |
1100 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap, | 1111 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap, |
1101 | action == FW_CTXT_ACTION_ADD); | 1112 | action == FW_CTXT_ACTION_ADD); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2eb6ebee4467..0d6a8b768a68 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -211,7 +211,9 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | |||
211 | return; | 211 | return; |
212 | 212 | ||
213 | IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); | 213 | IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); |
214 | WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap)); | 214 | spin_lock_bh(&mvm->refs_lock); |
215 | mvm->refs[ref_type]++; | ||
216 | spin_unlock_bh(&mvm->refs_lock); | ||
215 | iwl_trans_ref(mvm->trans); | 217 | iwl_trans_ref(mvm->trans); |
216 | } | 218 | } |
217 | 219 | ||
@@ -221,29 +223,35 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | |||
221 | return; | 223 | return; |
222 | 224 | ||
223 | IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); | 225 | IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); |
224 | WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap)); | 226 | spin_lock_bh(&mvm->refs_lock); |
227 | WARN_ON(!mvm->refs[ref_type]--); | ||
228 | spin_unlock_bh(&mvm->refs_lock); | ||
225 | iwl_trans_unref(mvm->trans); | 229 | iwl_trans_unref(mvm->trans); |
226 | } | 230 | } |
227 | 231 | ||
228 | static void | 232 | static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm, |
229 | iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) | 233 | enum iwl_mvm_ref_type except_ref) |
230 | { | 234 | { |
231 | int i; | 235 | int i, j; |
232 | 236 | ||
233 | if (!iwl_mvm_is_d0i3_supported(mvm)) | 237 | if (!iwl_mvm_is_d0i3_supported(mvm)) |
234 | return; | 238 | return; |
235 | 239 | ||
236 | for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) { | 240 | spin_lock_bh(&mvm->refs_lock); |
237 | if (ref == i) | 241 | for (i = 0; i < IWL_MVM_REF_COUNT; i++) { |
242 | if (except_ref == i || !mvm->refs[i]) | ||
238 | continue; | 243 | continue; |
239 | 244 | ||
240 | IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i); | 245 | IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n", |
241 | clear_bit(i, mvm->ref_bitmap); | 246 | i, mvm->refs[i]); |
242 | iwl_trans_unref(mvm->trans); | 247 | for (j = 0; j < mvm->refs[i]; j++) |
248 | iwl_trans_unref(mvm->trans); | ||
249 | mvm->refs[i] = 0; | ||
243 | } | 250 | } |
251 | spin_unlock_bh(&mvm->refs_lock); | ||
244 | } | 252 | } |
245 | 253 | ||
246 | static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | 254 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) |
247 | { | 255 | { |
248 | iwl_mvm_ref(mvm, ref_type); | 256 | iwl_mvm_ref(mvm, ref_type); |
249 | 257 | ||
@@ -321,13 +329,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
321 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | 329 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; |
322 | } | 330 | } |
323 | 331 | ||
324 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && | ||
325 | !iwlwifi_mod_params.uapsd_disable) { | ||
326 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; | ||
327 | hw->uapsd_queues = IWL_UAPSD_AC_INFO; | ||
328 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | ||
329 | } | ||
330 | |||
331 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 332 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) |
332 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; | 333 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; |
333 | 334 | ||
@@ -660,6 +661,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, | |||
660 | spin_unlock_bh(&mvm->time_event_lock); | 661 | spin_unlock_bh(&mvm->time_event_lock); |
661 | 662 | ||
662 | mvmvif->phy_ctxt = NULL; | 663 | mvmvif->phy_ctxt = NULL; |
664 | memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); | ||
663 | } | 665 | } |
664 | 666 | ||
665 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 667 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
@@ -668,11 +670,11 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | |||
668 | struct iwl_fw_error_dump_file *dump_file; | 670 | struct iwl_fw_error_dump_file *dump_file; |
669 | struct iwl_fw_error_dump_data *dump_data; | 671 | struct iwl_fw_error_dump_data *dump_data; |
670 | struct iwl_fw_error_dump_info *dump_info; | 672 | struct iwl_fw_error_dump_info *dump_info; |
673 | struct iwl_mvm_dump_ptrs *fw_error_dump; | ||
671 | const struct fw_img *img; | 674 | const struct fw_img *img; |
672 | u32 sram_len, sram_ofs; | 675 | u32 sram_len, sram_ofs; |
673 | u32 file_len, rxf_len; | 676 | u32 file_len, rxf_len; |
674 | unsigned long flags; | 677 | unsigned long flags; |
675 | u32 trans_len; | ||
676 | int reg_val; | 678 | int reg_val; |
677 | 679 | ||
678 | lockdep_assert_held(&mvm->mutex); | 680 | lockdep_assert_held(&mvm->mutex); |
@@ -680,6 +682,10 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | |||
680 | if (mvm->fw_error_dump) | 682 | if (mvm->fw_error_dump) |
681 | return; | 683 | return; |
682 | 684 | ||
685 | fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL); | ||
686 | if (!fw_error_dump) | ||
687 | return; | ||
688 | |||
683 | img = &mvm->fw->img[mvm->cur_ucode]; | 689 | img = &mvm->fw->img[mvm->cur_ucode]; |
684 | sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; | 690 | sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; |
685 | sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; | 691 | sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; |
@@ -697,18 +703,15 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | |||
697 | rxf_len + | 703 | rxf_len + |
698 | sizeof(*dump_info); | 704 | sizeof(*dump_info); |
699 | 705 | ||
700 | trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); | ||
701 | if (trans_len) | ||
702 | file_len += trans_len; | ||
703 | |||
704 | dump_file = vzalloc(file_len); | 706 | dump_file = vzalloc(file_len); |
705 | if (!dump_file) | 707 | if (!dump_file) { |
708 | kfree(fw_error_dump); | ||
706 | return; | 709 | return; |
710 | } | ||
707 | 711 | ||
708 | mvm->fw_error_dump = dump_file; | 712 | fw_error_dump->op_mode_ptr = dump_file; |
709 | 713 | ||
710 | dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); | 714 | dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); |
711 | dump_file->file_len = cpu_to_le32(file_len); | ||
712 | dump_data = (void *)dump_file->data; | 715 | dump_data = (void *)dump_file->data; |
713 | 716 | ||
714 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); | 717 | dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); |
@@ -749,14 +752,12 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | |||
749 | iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, | 752 | iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, |
750 | sram_len); | 753 | sram_len); |
751 | 754 | ||
752 | if (trans_len) { | 755 | fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); |
753 | void *buf = iwl_fw_error_next_data(dump_data); | 756 | fw_error_dump->op_mode_len = file_len; |
754 | u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, | 757 | if (fw_error_dump->trans_ptr) |
755 | trans_len); | 758 | file_len += fw_error_dump->trans_ptr->len; |
756 | dump_data = (void *)((u8 *)buf + real_trans_len); | 759 | dump_file->file_len = cpu_to_le32(file_len); |
757 | dump_file->file_len = | 760 | mvm->fw_error_dump = fw_error_dump; |
758 | cpu_to_le32(file_len - trans_len + real_trans_len); | ||
759 | } | ||
760 | } | 761 | } |
761 | #endif | 762 | #endif |
762 | 763 | ||
@@ -788,6 +789,12 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
788 | iwl_mvm_reset_phy_ctxts(mvm); | 789 | iwl_mvm_reset_phy_ctxts(mvm); |
789 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 790 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
790 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); | 791 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); |
792 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | ||
793 | memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); | ||
794 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); | ||
795 | memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old)); | ||
796 | memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk)); | ||
797 | memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk)); | ||
791 | 798 | ||
792 | ieee80211_wake_queues(mvm->hw); | 799 | ieee80211_wake_queues(mvm->hw); |
793 | 800 | ||
@@ -1399,6 +1406,28 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, | |||
1399 | } | 1406 | } |
1400 | #endif | 1407 | #endif |
1401 | 1408 | ||
1409 | static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) | ||
1410 | { | ||
1411 | struct ieee80211_sta *sta; | ||
1412 | struct iwl_mvm_sta *mvmsta; | ||
1413 | int i; | ||
1414 | |||
1415 | lockdep_assert_held(&mvm->mutex); | ||
1416 | |||
1417 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
1418 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
1419 | lockdep_is_held(&mvm->mutex)); | ||
1420 | if (!sta || IS_ERR(sta) || !sta->tdls) | ||
1421 | continue; | ||
1422 | |||
1423 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
1424 | ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, | ||
1425 | NL80211_TDLS_TEARDOWN, | ||
1426 | WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, | ||
1427 | GFP_KERNEL); | ||
1428 | } | ||
1429 | } | ||
1430 | |||
1402 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | 1431 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, |
1403 | struct ieee80211_vif *vif, | 1432 | struct ieee80211_vif *vif, |
1404 | struct ieee80211_bss_conf *bss_conf, | 1433 | struct ieee80211_bss_conf *bss_conf, |
@@ -1494,14 +1523,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
1494 | */ | 1523 | */ |
1495 | iwl_mvm_remove_time_event(mvm, mvmvif, | 1524 | iwl_mvm_remove_time_event(mvm, mvmvif, |
1496 | &mvmvif->time_event_data); | 1525 | &mvmvif->time_event_data); |
1497 | iwl_mvm_sf_update(mvm, vif, false); | ||
1498 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); | ||
1499 | } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | | 1526 | } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | |
1500 | BSS_CHANGED_QOS)) { | 1527 | BSS_CHANGED_QOS)) { |
1501 | ret = iwl_mvm_power_update_mac(mvm); | 1528 | ret = iwl_mvm_power_update_mac(mvm); |
1502 | if (ret) | 1529 | if (ret) |
1503 | IWL_ERR(mvm, "failed to update power mode\n"); | 1530 | IWL_ERR(mvm, "failed to update power mode\n"); |
1504 | } | 1531 | } |
1532 | |||
1533 | if (changes & BSS_CHANGED_BEACON_INFO) { | ||
1534 | iwl_mvm_sf_update(mvm, vif, false); | ||
1535 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); | ||
1536 | } | ||
1537 | |||
1505 | if (changes & BSS_CHANGED_TXPOWER) { | 1538 | if (changes & BSS_CHANGED_TXPOWER) { |
1506 | IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", | 1539 | IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", |
1507 | bss_conf->txpower); | 1540 | bss_conf->txpower); |
@@ -1533,6 +1566,14 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
1533 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1566 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1534 | int ret; | 1567 | int ret; |
1535 | 1568 | ||
1569 | /* | ||
1570 | * iwl_mvm_mac_ctxt_add() might read directly from the device | ||
1571 | * (the system time), so make sure it is available. | ||
1572 | */ | ||
1573 | ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP); | ||
1574 | if (ret) | ||
1575 | return ret; | ||
1576 | |||
1536 | mutex_lock(&mvm->mutex); | 1577 | mutex_lock(&mvm->mutex); |
1537 | 1578 | ||
1538 | /* Send the beacon template */ | 1579 | /* Send the beacon template */ |
@@ -1581,6 +1622,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
1581 | 1622 | ||
1582 | iwl_mvm_bt_coex_vif_change(mvm); | 1623 | iwl_mvm_bt_coex_vif_change(mvm); |
1583 | 1624 | ||
1625 | /* we don't support TDLS during DCM */ | ||
1626 | if (iwl_mvm_phy_ctx_count(mvm) > 1) | ||
1627 | iwl_mvm_teardown_tdls_peers(mvm); | ||
1628 | |||
1584 | mutex_unlock(&mvm->mutex); | 1629 | mutex_unlock(&mvm->mutex); |
1585 | return 0; | 1630 | return 0; |
1586 | 1631 | ||
@@ -1594,6 +1639,7 @@ out_remove: | |||
1594 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 1639 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
1595 | out_unlock: | 1640 | out_unlock: |
1596 | mutex_unlock(&mvm->mutex); | 1641 | mutex_unlock(&mvm->mutex); |
1642 | iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP); | ||
1597 | return ret; | 1643 | return ret; |
1598 | } | 1644 | } |
1599 | 1645 | ||
@@ -1671,6 +1717,14 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | |||
1671 | { | 1717 | { |
1672 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1718 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1673 | 1719 | ||
1720 | /* | ||
1721 | * iwl_mvm_bss_info_changed_station() might call | ||
1722 | * iwl_mvm_protect_session(), which reads directly from | ||
1723 | * the device (the system time), so make sure it is available. | ||
1724 | */ | ||
1725 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED)) | ||
1726 | return; | ||
1727 | |||
1674 | mutex_lock(&mvm->mutex); | 1728 | mutex_lock(&mvm->mutex); |
1675 | 1729 | ||
1676 | if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) | 1730 | if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) |
@@ -1690,8 +1744,50 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | |||
1690 | } | 1744 | } |
1691 | 1745 | ||
1692 | mutex_unlock(&mvm->mutex); | 1746 | mutex_unlock(&mvm->mutex); |
1747 | iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED); | ||
1693 | } | 1748 | } |
1694 | 1749 | ||
1750 | static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm, | ||
1751 | enum iwl_scan_status scan_type) | ||
1752 | { | ||
1753 | int ret; | ||
1754 | bool wait_for_handlers = false; | ||
1755 | |||
1756 | mutex_lock(&mvm->mutex); | ||
1757 | |||
1758 | if (mvm->scan_status != scan_type) { | ||
1759 | ret = 0; | ||
1760 | /* make sure there are no pending notifications */ | ||
1761 | wait_for_handlers = true; | ||
1762 | goto out; | ||
1763 | } | ||
1764 | |||
1765 | switch (scan_type) { | ||
1766 | case IWL_MVM_SCAN_SCHED: | ||
1767 | ret = iwl_mvm_scan_offload_stop(mvm, true); | ||
1768 | break; | ||
1769 | case IWL_MVM_SCAN_OS: | ||
1770 | ret = iwl_mvm_cancel_scan(mvm); | ||
1771 | break; | ||
1772 | case IWL_MVM_SCAN_NONE: | ||
1773 | default: | ||
1774 | WARN_ON_ONCE(1); | ||
1775 | ret = -EINVAL; | ||
1776 | break; | ||
1777 | } | ||
1778 | if (ret) | ||
1779 | goto out; | ||
1780 | |||
1781 | wait_for_handlers = true; | ||
1782 | out: | ||
1783 | mutex_unlock(&mvm->mutex); | ||
1784 | |||
1785 | /* make sure we consume the completion notification */ | ||
1786 | if (wait_for_handlers) | ||
1787 | iwl_mvm_wait_for_async_handlers(mvm); | ||
1788 | |||
1789 | return ret; | ||
1790 | } | ||
1695 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | 1791 | static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, |
1696 | struct ieee80211_vif *vif, | 1792 | struct ieee80211_vif *vif, |
1697 | struct ieee80211_scan_request *hw_req) | 1793 | struct ieee80211_scan_request *hw_req) |
@@ -1704,19 +1800,13 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1704 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) | 1800 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) |
1705 | return -EINVAL; | 1801 | return -EINVAL; |
1706 | 1802 | ||
1803 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); | ||
1804 | if (ret) | ||
1805 | return ret; | ||
1806 | |||
1707 | mutex_lock(&mvm->mutex); | 1807 | mutex_lock(&mvm->mutex); |
1708 | 1808 | ||
1709 | switch (mvm->scan_status) { | 1809 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { |
1710 | case IWL_MVM_SCAN_SCHED: | ||
1711 | ret = iwl_mvm_scan_offload_stop(mvm, true); | ||
1712 | if (ret) { | ||
1713 | ret = -EBUSY; | ||
1714 | goto out; | ||
1715 | } | ||
1716 | break; | ||
1717 | case IWL_MVM_SCAN_NONE: | ||
1718 | break; | ||
1719 | default: | ||
1720 | ret = -EBUSY; | 1810 | ret = -EBUSY; |
1721 | goto out; | 1811 | goto out; |
1722 | } | 1812 | } |
@@ -1732,8 +1822,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1732 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | 1822 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); |
1733 | out: | 1823 | out: |
1734 | mutex_unlock(&mvm->mutex); | 1824 | mutex_unlock(&mvm->mutex); |
1735 | /* make sure to flush the Rx handler before the next scan arrives */ | ||
1736 | iwl_mvm_wait_for_async_handlers(mvm); | ||
1737 | return ret; | 1825 | return ret; |
1738 | } | 1826 | } |
1739 | 1827 | ||
@@ -1885,28 +1973,6 @@ static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, | |||
1885 | iwl_mvm_power_update_mac(mvm); | 1973 | iwl_mvm_power_update_mac(mvm); |
1886 | } | 1974 | } |
1887 | 1975 | ||
1888 | static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) | ||
1889 | { | ||
1890 | struct ieee80211_sta *sta; | ||
1891 | struct iwl_mvm_sta *mvmsta; | ||
1892 | int i; | ||
1893 | |||
1894 | lockdep_assert_held(&mvm->mutex); | ||
1895 | |||
1896 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
1897 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
1898 | lockdep_is_held(&mvm->mutex)); | ||
1899 | if (!sta || IS_ERR(sta) || !sta->tdls) | ||
1900 | continue; | ||
1901 | |||
1902 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
1903 | ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, | ||
1904 | NL80211_TDLS_TEARDOWN, | ||
1905 | WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, | ||
1906 | GFP_KERNEL); | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | 1976 | static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, |
1911 | struct ieee80211_vif *vif, | 1977 | struct ieee80211_vif *vif, |
1912 | struct ieee80211_sta *sta, | 1978 | struct ieee80211_sta *sta, |
@@ -2065,10 +2131,19 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, | |||
2065 | if (WARN_ON_ONCE(vif->bss_conf.assoc)) | 2131 | if (WARN_ON_ONCE(vif->bss_conf.assoc)) |
2066 | return; | 2132 | return; |
2067 | 2133 | ||
2134 | /* | ||
2135 | * iwl_mvm_protect_session() reads directly from the device | ||
2136 | * (the system time), so make sure it is available. | ||
2137 | */ | ||
2138 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX)) | ||
2139 | return; | ||
2140 | |||
2068 | mutex_lock(&mvm->mutex); | 2141 | mutex_lock(&mvm->mutex); |
2069 | /* Try really hard to protect the session and hear a beacon */ | 2142 | /* Try really hard to protect the session and hear a beacon */ |
2070 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); | 2143 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); |
2071 | mutex_unlock(&mvm->mutex); | 2144 | mutex_unlock(&mvm->mutex); |
2145 | |||
2146 | iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); | ||
2072 | } | 2147 | } |
2073 | 2148 | ||
2074 | static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | 2149 | static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, |
@@ -2077,10 +2152,19 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, | |||
2077 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2152 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2078 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; | 2153 | u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; |
2079 | 2154 | ||
2155 | /* | ||
2156 | * iwl_mvm_protect_session() reads directly from the device | ||
2157 | * (the system time), so make sure it is available. | ||
2158 | */ | ||
2159 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) | ||
2160 | return; | ||
2161 | |||
2080 | mutex_lock(&mvm->mutex); | 2162 | mutex_lock(&mvm->mutex); |
2081 | /* Protect the session to hear the TDLS setup response on the channel */ | 2163 | /* Protect the session to hear the TDLS setup response on the channel */ |
2082 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100); | 2164 | iwl_mvm_protect_session(mvm, vif, duration, duration, 100); |
2083 | mutex_unlock(&mvm->mutex); | 2165 | mutex_unlock(&mvm->mutex); |
2166 | |||
2167 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); | ||
2084 | } | 2168 | } |
2085 | 2169 | ||
2086 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | 2170 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, |
@@ -2091,6 +2175,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2091 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2175 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2092 | int ret; | 2176 | int ret; |
2093 | 2177 | ||
2178 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); | ||
2179 | if (ret) | ||
2180 | return ret; | ||
2181 | |||
2094 | mutex_lock(&mvm->mutex); | 2182 | mutex_lock(&mvm->mutex); |
2095 | 2183 | ||
2096 | if (!iwl_mvm_is_idle(mvm)) { | 2184 | if (!iwl_mvm_is_idle(mvm)) { |
@@ -2098,26 +2186,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2098 | goto out; | 2186 | goto out; |
2099 | } | 2187 | } |
2100 | 2188 | ||
2101 | switch (mvm->scan_status) { | 2189 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { |
2102 | case IWL_MVM_SCAN_OS: | ||
2103 | IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n"); | ||
2104 | ret = iwl_mvm_cancel_scan(mvm); | ||
2105 | if (ret) { | ||
2106 | ret = -EBUSY; | ||
2107 | goto out; | ||
2108 | } | ||
2109 | |||
2110 | /* | ||
2111 | * iwl_mvm_rx_scan_complete() will be called soon but will | ||
2112 | * not reset the scan status as it won't be IWL_MVM_SCAN_OS | ||
2113 | * any more since we queue the next scan immediately (below). | ||
2114 | * We make sure it is called before the next scan starts by | ||
2115 | * flushing the async-handlers work. | ||
2116 | */ | ||
2117 | break; | ||
2118 | case IWL_MVM_SCAN_NONE: | ||
2119 | break; | ||
2120 | default: | ||
2121 | ret = -EBUSY; | 2190 | ret = -EBUSY; |
2122 | goto out; | 2191 | goto out; |
2123 | } | 2192 | } |
@@ -2145,8 +2214,6 @@ err: | |||
2145 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 2214 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
2146 | out: | 2215 | out: |
2147 | mutex_unlock(&mvm->mutex); | 2216 | mutex_unlock(&mvm->mutex); |
2148 | /* make sure to flush the Rx handler before the next scan arrives */ | ||
2149 | iwl_mvm_wait_for_async_handlers(mvm); | ||
2150 | return ret; | 2217 | return ret; |
2151 | } | 2218 | } |
2152 | 2219 | ||
@@ -2266,6 +2333,119 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, | |||
2266 | } | 2333 | } |
2267 | 2334 | ||
2268 | 2335 | ||
2336 | static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait, | ||
2337 | struct iwl_rx_packet *pkt, void *data) | ||
2338 | { | ||
2339 | struct iwl_mvm *mvm = | ||
2340 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
2341 | struct iwl_hs20_roc_res *resp; | ||
2342 | int resp_len = iwl_rx_packet_payload_len(pkt); | ||
2343 | struct iwl_mvm_time_event_data *te_data = data; | ||
2344 | |||
2345 | if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD)) | ||
2346 | return true; | ||
2347 | |||
2348 | if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { | ||
2349 | IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n"); | ||
2350 | return true; | ||
2351 | } | ||
2352 | |||
2353 | resp = (void *)pkt->data; | ||
2354 | |||
2355 | IWL_DEBUG_TE(mvm, | ||
2356 | "Aux ROC: Recieved response from ucode: status=%d uid=%d\n", | ||
2357 | resp->status, resp->event_unique_id); | ||
2358 | |||
2359 | te_data->uid = le32_to_cpu(resp->event_unique_id); | ||
2360 | IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n", | ||
2361 | te_data->uid); | ||
2362 | |||
2363 | spin_lock_bh(&mvm->time_event_lock); | ||
2364 | list_add_tail(&te_data->list, &mvm->aux_roc_te_list); | ||
2365 | spin_unlock_bh(&mvm->time_event_lock); | ||
2366 | |||
2367 | return true; | ||
2368 | } | ||
2369 | |||
2370 | #define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000 | ||
2371 | static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, | ||
2372 | struct ieee80211_channel *channel, | ||
2373 | struct ieee80211_vif *vif, | ||
2374 | int duration) | ||
2375 | { | ||
2376 | int res, time_reg = DEVICE_SYSTEM_TIME_REG; | ||
2377 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
2378 | struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data; | ||
2379 | static const u8 time_event_response[] = { HOT_SPOT_CMD }; | ||
2380 | struct iwl_notification_wait wait_time_event; | ||
2381 | struct iwl_hs20_roc_req aux_roc_req = { | ||
2382 | .action = cpu_to_le32(FW_CTXT_ACTION_ADD), | ||
2383 | .id_and_color = | ||
2384 | cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)), | ||
2385 | .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id), | ||
2386 | /* Set the channel info data */ | ||
2387 | .channel_info.band = (channel->band == IEEE80211_BAND_2GHZ) ? | ||
2388 | PHY_BAND_24 : PHY_BAND_5, | ||
2389 | .channel_info.channel = channel->hw_value, | ||
2390 | .channel_info.width = PHY_VHT_CHANNEL_MODE20, | ||
2391 | /* Set the time and duration */ | ||
2392 | .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)), | ||
2393 | .apply_time_max_delay = | ||
2394 | cpu_to_le32(MSEC_TO_TU(AUX_ROC_MAX_DELAY_ON_CHANNEL)), | ||
2395 | .duration = cpu_to_le32(MSEC_TO_TU(duration)), | ||
2396 | }; | ||
2397 | |||
2398 | /* Set the node address */ | ||
2399 | memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); | ||
2400 | |||
2401 | te_data->vif = vif; | ||
2402 | te_data->duration = duration; | ||
2403 | te_data->id = HOT_SPOT_CMD; | ||
2404 | |||
2405 | lockdep_assert_held(&mvm->mutex); | ||
2406 | |||
2407 | spin_lock_bh(&mvm->time_event_lock); | ||
2408 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
2409 | spin_unlock_bh(&mvm->time_event_lock); | ||
2410 | |||
2411 | /* | ||
2412 | * Use a notification wait, which really just processes the | ||
2413 | * command response and doesn't wait for anything, in order | ||
2414 | * to be able to process the response and get the UID inside | ||
2415 | * the RX path. Using CMD_WANT_SKB doesn't work because it | ||
2416 | * stores the buffer and then wakes up this thread, by which | ||
2417 | * time another notification (that the time event started) | ||
2418 | * might already be processed unsuccessfully. | ||
2419 | */ | ||
2420 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
2421 | time_event_response, | ||
2422 | ARRAY_SIZE(time_event_response), | ||
2423 | iwl_mvm_rx_aux_roc, te_data); | ||
2424 | |||
2425 | res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req), | ||
2426 | &aux_roc_req); | ||
2427 | |||
2428 | if (res) { | ||
2429 | IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res); | ||
2430 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
2431 | goto out_clear_te; | ||
2432 | } | ||
2433 | |||
2434 | /* No need to wait for anything, so just pass 1 (0 isn't valid) */ | ||
2435 | res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1); | ||
2436 | /* should never fail */ | ||
2437 | WARN_ON_ONCE(res); | ||
2438 | |||
2439 | if (res) { | ||
2440 | out_clear_te: | ||
2441 | spin_lock_bh(&mvm->time_event_lock); | ||
2442 | iwl_mvm_te_clear_data(mvm, te_data); | ||
2443 | spin_unlock_bh(&mvm->time_event_lock); | ||
2444 | } | ||
2445 | |||
2446 | return res; | ||
2447 | } | ||
2448 | |||
2269 | static int iwl_mvm_roc(struct ieee80211_hw *hw, | 2449 | static int iwl_mvm_roc(struct ieee80211_hw *hw, |
2270 | struct ieee80211_vif *vif, | 2450 | struct ieee80211_vif *vif, |
2271 | struct ieee80211_channel *channel, | 2451 | struct ieee80211_channel *channel, |
@@ -2281,8 +2461,17 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
2281 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, | 2461 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, |
2282 | duration, type); | 2462 | duration, type); |
2283 | 2463 | ||
2284 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { | 2464 | switch (vif->type) { |
2285 | IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); | 2465 | case NL80211_IFTYPE_STATION: |
2466 | /* Use aux roc framework (HS20) */ | ||
2467 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | ||
2468 | vif, duration); | ||
2469 | return ret; | ||
2470 | case NL80211_IFTYPE_P2P_DEVICE: | ||
2471 | /* handle below */ | ||
2472 | break; | ||
2473 | default: | ||
2474 | IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type); | ||
2286 | return -EINVAL; | 2475 | return -EINVAL; |
2287 | } | 2476 | } |
2288 | 2477 | ||
@@ -2661,6 +2850,10 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, | |||
2661 | goto out_remove; | 2850 | goto out_remove; |
2662 | } | 2851 | } |
2663 | 2852 | ||
2853 | /* we don't support TDLS during DCM - can be caused by channel switch */ | ||
2854 | if (iwl_mvm_phy_ctx_count(mvm) > 1) | ||
2855 | iwl_mvm_teardown_tdls_peers(mvm); | ||
2856 | |||
2664 | goto out; | 2857 | goto out; |
2665 | 2858 | ||
2666 | out_remove: | 2859 | out_remove: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 785e5232c757..2e73d3bd7757 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -82,6 +82,8 @@ | |||
82 | /* RSSI offset for WkP */ | 82 | /* RSSI offset for WkP */ |
83 | #define IWL_RSSI_OFFSET 50 | 83 | #define IWL_RSSI_OFFSET 50 |
84 | #define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 | 84 | #define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 |
85 | /* A TimeUnit is 1024 microsecond */ | ||
86 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | ||
85 | 87 | ||
86 | /* | 88 | /* |
87 | * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" | 89 | * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" |
@@ -126,6 +128,21 @@ struct iwl_mvm_mod_params { | |||
126 | }; | 128 | }; |
127 | extern struct iwl_mvm_mod_params iwlmvm_mod_params; | 129 | extern struct iwl_mvm_mod_params iwlmvm_mod_params; |
128 | 130 | ||
131 | /** | ||
132 | * struct iwl_mvm_dump_ptrs - set of pointers needed for the fw-error-dump | ||
133 | * | ||
134 | * @op_mode_ptr: pointer to the buffer coming from the mvm op_mode | ||
135 | * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the | ||
136 | * transport's data. | ||
137 | * @trans_len: length of the valid data in trans_ptr | ||
138 | * @op_mode_len: length of the valid data in op_mode_ptr | ||
139 | */ | ||
140 | struct iwl_mvm_dump_ptrs { | ||
141 | struct iwl_trans_dump_data *trans_ptr; | ||
142 | void *op_mode_ptr; | ||
143 | u32 op_mode_len; | ||
144 | }; | ||
145 | |||
129 | struct iwl_mvm_phy_ctxt { | 146 | struct iwl_mvm_phy_ctxt { |
130 | u16 id; | 147 | u16 id; |
131 | u16 color; | 148 | u16 color; |
@@ -249,6 +266,15 @@ enum iwl_mvm_ref_type { | |||
249 | IWL_MVM_REF_TX, | 266 | IWL_MVM_REF_TX, |
250 | IWL_MVM_REF_TX_AGG, | 267 | IWL_MVM_REF_TX_AGG, |
251 | IWL_MVM_REF_ADD_IF, | 268 | IWL_MVM_REF_ADD_IF, |
269 | IWL_MVM_REF_START_AP, | ||
270 | IWL_MVM_REF_BSS_CHANGED, | ||
271 | IWL_MVM_REF_PREPARE_TX, | ||
272 | IWL_MVM_REF_PROTECT_TDLS, | ||
273 | IWL_MVM_REF_CHECK_CTKILL, | ||
274 | IWL_MVM_REF_PRPH_READ, | ||
275 | IWL_MVM_REF_PRPH_WRITE, | ||
276 | IWL_MVM_REF_NMI, | ||
277 | IWL_MVM_REF_TM_CMD, | ||
252 | IWL_MVM_REF_EXIT_WORK, | 278 | IWL_MVM_REF_EXIT_WORK, |
253 | 279 | ||
254 | IWL_MVM_REF_COUNT, | 280 | IWL_MVM_REF_COUNT, |
@@ -327,6 +353,7 @@ struct iwl_mvm_vif { | |||
327 | */ | 353 | */ |
328 | struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; | 354 | struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; |
329 | struct iwl_mvm_time_event_data time_event_data; | 355 | struct iwl_mvm_time_event_data time_event_data; |
356 | struct iwl_mvm_time_event_data hs_time_event_data; | ||
330 | 357 | ||
331 | struct iwl_mvm_int_sta bcast_sta; | 358 | struct iwl_mvm_int_sta bcast_sta; |
332 | 359 | ||
@@ -606,14 +633,15 @@ struct iwl_mvm { | |||
606 | */ | 633 | */ |
607 | unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; | 634 | unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; |
608 | 635 | ||
609 | /* A bitmap of reference types taken by the driver. */ | 636 | /* references taken by the driver and spinlock protecting them */ |
610 | unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)]; | 637 | spinlock_t refs_lock; |
638 | u8 refs[IWL_MVM_REF_COUNT]; | ||
611 | 639 | ||
612 | u8 vif_count; | 640 | u8 vif_count; |
613 | 641 | ||
614 | /* -1 for always, 0 for never, >0 for that many times */ | 642 | /* -1 for always, 0 for never, >0 for that many times */ |
615 | s8 restart_fw; | 643 | s8 restart_fw; |
616 | void *fw_error_dump; | 644 | struct iwl_mvm_dump_ptrs *fw_error_dump; |
617 | 645 | ||
618 | #ifdef CONFIG_IWLWIFI_LEDS | 646 | #ifdef CONFIG_IWLWIFI_LEDS |
619 | struct led_classdev led; | 647 | struct led_classdev led; |
@@ -647,7 +675,8 @@ struct iwl_mvm { | |||
647 | wait_queue_head_t d0i3_exit_waitq; | 675 | wait_queue_head_t d0i3_exit_waitq; |
648 | 676 | ||
649 | /* BT-Coex */ | 677 | /* BT-Coex */ |
650 | u8 bt_kill_msk; | 678 | u8 bt_ack_kill_msk[NUM_PHY_CTX]; |
679 | u8 bt_cts_kill_msk[NUM_PHY_CTX]; | ||
651 | 680 | ||
652 | struct iwl_bt_coex_profile_notif_old last_bt_notif_old; | 681 | struct iwl_bt_coex_profile_notif_old last_bt_notif_old; |
653 | struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old; | 682 | struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old; |
@@ -659,6 +688,9 @@ struct iwl_mvm { | |||
659 | u8 bt_tx_prio; | 688 | u8 bt_tx_prio; |
660 | enum iwl_bt_force_ant_mode bt_force_ant_mode; | 689 | enum iwl_bt_force_ant_mode bt_force_ant_mode; |
661 | 690 | ||
691 | /* Aux ROC */ | ||
692 | struct list_head aux_roc_te_list; | ||
693 | |||
662 | /* Thermal Throttling and CTkill */ | 694 | /* Thermal Throttling and CTkill */ |
663 | struct iwl_mvm_tt_mgmt thermal_throttle; | 695 | struct iwl_mvm_tt_mgmt thermal_throttle; |
664 | s32 temperature; /* Celsius */ | 696 | s32 temperature; /* Celsius */ |
@@ -697,6 +729,7 @@ enum iwl_mvm_status { | |||
697 | IWL_MVM_STATUS_ROC_RUNNING, | 729 | IWL_MVM_STATUS_ROC_RUNNING, |
698 | IWL_MVM_STATUS_IN_HW_RESTART, | 730 | IWL_MVM_STATUS_IN_HW_RESTART, |
699 | IWL_MVM_STATUS_IN_D0I3, | 731 | IWL_MVM_STATUS_IN_D0I3, |
732 | IWL_MVM_STATUS_ROC_AUX_RUNNING, | ||
700 | }; | 733 | }; |
701 | 734 | ||
702 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | 735 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) |
@@ -988,6 +1021,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
988 | /* D0i3 */ | 1021 | /* D0i3 */ |
989 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1022 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
990 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | 1023 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); |
1024 | int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | ||
991 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); | 1025 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); |
992 | int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); | 1026 | int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); |
993 | 1027 | ||
@@ -1029,12 +1063,14 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, | |||
1029 | 1063 | ||
1030 | enum iwl_bt_kill_msk { | 1064 | enum iwl_bt_kill_msk { |
1031 | BT_KILL_MSK_DEFAULT, | 1065 | BT_KILL_MSK_DEFAULT, |
1032 | BT_KILL_MSK_SCO_HID_A2DP, | 1066 | BT_KILL_MSK_NEVER, |
1033 | BT_KILL_MSK_REDUCED_TXPOW, | 1067 | BT_KILL_MSK_ALWAYS, |
1034 | BT_KILL_MSK_MAX, | 1068 | BT_KILL_MSK_MAX, |
1035 | }; | 1069 | }; |
1036 | extern const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX]; | 1070 | |
1037 | extern const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX]; | 1071 | extern const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; |
1072 | extern const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; | ||
1073 | extern const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX]; | ||
1038 | 1074 | ||
1039 | /* beacon filtering */ | 1075 | /* beacon filtering */ |
1040 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1076 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index b04805ccb443..cfdd314fdd5d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -265,7 +265,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) | |||
265 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { | 265 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
266 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || | 266 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || |
267 | !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { | 267 | !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { |
268 | IWL_ERR(mvm, "Can't parse empty NVM sections\n"); | 268 | IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n"); |
269 | return NULL; | 269 | return NULL; |
270 | } | 270 | } |
271 | } else { | 271 | } else { |
@@ -273,7 +273,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) | |||
273 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || | 273 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || |
274 | !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { | 274 | !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { |
275 | IWL_ERR(mvm, | 275 | IWL_ERR(mvm, |
276 | "Can't parse empty family 8000 NVM sections\n"); | 276 | "Can't parse empty family 8000 OTP/NVM sections\n"); |
277 | return NULL; | 277 | return NULL; |
278 | } | 278 | } |
279 | /* MAC_OVERRIDE or at least HW section must exist */ | 279 | /* MAC_OVERRIDE or at least HW section must exist */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 7d7b2fbe7cd1..610dbcb0dc27 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -289,6 +289,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
289 | CMD(MATCH_FOUND_NOTIFICATION), | 289 | CMD(MATCH_FOUND_NOTIFICATION), |
290 | CMD(SCAN_OFFLOAD_REQUEST_CMD), | 290 | CMD(SCAN_OFFLOAD_REQUEST_CMD), |
291 | CMD(SCAN_OFFLOAD_ABORT_CMD), | 291 | CMD(SCAN_OFFLOAD_ABORT_CMD), |
292 | CMD(HOT_SPOT_CMD), | ||
292 | CMD(SCAN_OFFLOAD_COMPLETE), | 293 | CMD(SCAN_OFFLOAD_COMPLETE), |
293 | CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), | 294 | CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), |
294 | CMD(SCAN_ITERATION_COMPLETE), | 295 | CMD(SCAN_ITERATION_COMPLETE), |
@@ -391,6 +392,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
391 | if (!hw) | 392 | if (!hw) |
392 | return NULL; | 393 | return NULL; |
393 | 394 | ||
395 | if (cfg->max_rx_agg_size) | ||
396 | hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; | ||
397 | |||
394 | op_mode = hw->priv; | 398 | op_mode = hw->priv; |
395 | op_mode->ops = &iwl_mvm_ops; | 399 | op_mode->ops = &iwl_mvm_ops; |
396 | 400 | ||
@@ -416,6 +420,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
416 | mutex_init(&mvm->d0i3_suspend_mutex); | 420 | mutex_init(&mvm->d0i3_suspend_mutex); |
417 | spin_lock_init(&mvm->async_handlers_lock); | 421 | spin_lock_init(&mvm->async_handlers_lock); |
418 | INIT_LIST_HEAD(&mvm->time_event_list); | 422 | INIT_LIST_HEAD(&mvm->time_event_list); |
423 | INIT_LIST_HEAD(&mvm->aux_roc_te_list); | ||
419 | INIT_LIST_HEAD(&mvm->async_handlers_list); | 424 | INIT_LIST_HEAD(&mvm->async_handlers_list); |
420 | spin_lock_init(&mvm->time_event_lock); | 425 | spin_lock_init(&mvm->time_event_lock); |
421 | 426 | ||
@@ -425,6 +430,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
425 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); | 430 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); |
426 | 431 | ||
427 | spin_lock_init(&mvm->d0i3_tx_lock); | 432 | spin_lock_init(&mvm->d0i3_tx_lock); |
433 | spin_lock_init(&mvm->refs_lock); | ||
428 | skb_queue_head_init(&mvm->d0i3_tx); | 434 | skb_queue_head_init(&mvm->d0i3_tx); |
429 | init_waitqueue_head(&mvm->d0i3_exit_waitq); | 435 | init_waitqueue_head(&mvm->d0i3_exit_waitq); |
430 | 436 | ||
@@ -539,7 +545,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
539 | memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); | 545 | memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); |
540 | 546 | ||
541 | /* rpm starts with a taken ref. only set the appropriate bit here. */ | 547 | /* rpm starts with a taken ref. only set the appropriate bit here. */ |
542 | set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap); | 548 | mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1; |
543 | 549 | ||
544 | return op_mode; | 550 | return op_mode; |
545 | 551 | ||
@@ -567,7 +573,11 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
567 | ieee80211_unregister_hw(mvm->hw); | 573 | ieee80211_unregister_hw(mvm->hw); |
568 | 574 | ||
569 | kfree(mvm->scan_cmd); | 575 | kfree(mvm->scan_cmd); |
570 | vfree(mvm->fw_error_dump); | 576 | if (mvm->fw_error_dump) { |
577 | vfree(mvm->fw_error_dump->op_mode_ptr); | ||
578 | vfree(mvm->fw_error_dump->trans_ptr); | ||
579 | kfree(mvm->fw_error_dump); | ||
580 | } | ||
571 | kfree(mvm->mcast_filter_cmd); | 581 | kfree(mvm->mcast_filter_cmd); |
572 | mvm->mcast_filter_cmd = NULL; | 582 | mvm->mcast_filter_cmd = NULL; |
573 | 583 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 812813964847..763548880399 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -98,23 +98,21 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
98 | bool update) | 98 | bool update) |
99 | { | 99 | { |
100 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 100 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
101 | struct iwl_mvm_add_sta_cmd add_sta_cmd; | 101 | struct iwl_mvm_add_sta_cmd add_sta_cmd = { |
102 | .sta_id = mvm_sta->sta_id, | ||
103 | .mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color), | ||
104 | .add_modify = update ? 1 : 0, | ||
105 | .station_flags_msk = cpu_to_le32(STA_FLG_FAT_EN_MSK | | ||
106 | STA_FLG_MIMO_EN_MSK), | ||
107 | }; | ||
102 | int ret; | 108 | int ret; |
103 | u32 status; | 109 | u32 status; |
104 | u32 agg_size = 0, mpdu_dens = 0; | 110 | u32 agg_size = 0, mpdu_dens = 0; |
105 | 111 | ||
106 | memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); | ||
107 | |||
108 | add_sta_cmd.sta_id = mvm_sta->sta_id; | ||
109 | add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | ||
110 | if (!update) { | 112 | if (!update) { |
111 | add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); | 113 | add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); |
112 | memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | 114 | memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); |
113 | } | 115 | } |
114 | add_sta_cmd.add_modify = update ? 1 : 0; | ||
115 | |||
116 | add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK | | ||
117 | STA_FLG_MIMO_EN_MSK); | ||
118 | 116 | ||
119 | switch (sta->bandwidth) { | 117 | switch (sta->bandwidth) { |
120 | case IEEE80211_STA_RX_BW_160: | 118 | case IEEE80211_STA_RX_BW_160: |
@@ -528,8 +526,12 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | |||
528 | 526 | ||
529 | lockdep_assert_held(&mvm->mutex); | 527 | lockdep_assert_held(&mvm->mutex); |
530 | 528 | ||
531 | /* Add the aux station, but without any queues */ | 529 | /* Map Aux queue to fifo - needs to happen before adding Aux station */ |
532 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0, | 530 | iwl_trans_ac_txq_enable(mvm->trans, mvm->aux_queue, |
531 | IWL_MVM_TX_FIFO_MCAST); | ||
532 | |||
533 | /* Allocate aux station and assign to it the aux queue */ | ||
534 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), | ||
533 | NL80211_IFTYPE_UNSPECIFIED); | 535 | NL80211_IFTYPE_UNSPECIFIED); |
534 | if (ret) | 536 | if (ret) |
535 | return ret; | 537 | return ret; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index ae52613b97f2..33e5041f1efc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -72,9 +72,6 @@ | |||
72 | #include "iwl-io.h" | 72 | #include "iwl-io.h" |
73 | #include "iwl-prph.h" | 73 | #include "iwl-prph.h" |
74 | 74 | ||
75 | /* A TimeUnit is 1024 microsecond */ | ||
76 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | ||
77 | |||
78 | /* | 75 | /* |
79 | * For the high priority TE use a time event type that has similar priority to | 76 | * For the high priority TE use a time event type that has similar priority to |
80 | * the FW's action scan priority. | 77 | * the FW's action scan priority. |
@@ -100,6 +97,21 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | |||
100 | void iwl_mvm_roc_done_wk(struct work_struct *wk) | 97 | void iwl_mvm_roc_done_wk(struct work_struct *wk) |
101 | { | 98 | { |
102 | struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk); | 99 | struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk); |
100 | u32 queues = 0; | ||
101 | |||
102 | /* | ||
103 | * Clear the ROC_RUNNING /ROC_AUX_RUNNING status bit. | ||
104 | * This will cause the TX path to drop offchannel transmissions. | ||
105 | * That would also be done by mac80211, but it is racy, in particular | ||
106 | * in the case that the time event actually completed in the firmware | ||
107 | * (which is handled in iwl_mvm_te_handle_notif). | ||
108 | */ | ||
109 | if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) | ||
110 | queues |= BIT(IWL_MVM_OFFCHANNEL_QUEUE); | ||
111 | if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) | ||
112 | queues |= BIT(mvm->aux_queue); | ||
113 | |||
114 | iwl_mvm_unref(mvm, IWL_MVM_REF_ROC); | ||
103 | 115 | ||
104 | synchronize_net(); | 116 | synchronize_net(); |
105 | 117 | ||
@@ -113,22 +125,12 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) | |||
113 | * issue as it will have to complete before the next command is | 125 | * issue as it will have to complete before the next command is |
114 | * executed, and a new time event means a new command. | 126 | * executed, and a new time event means a new command. |
115 | */ | 127 | */ |
116 | iwl_mvm_flush_tx_path(mvm, BIT(IWL_MVM_OFFCHANNEL_QUEUE), false); | 128 | iwl_mvm_flush_tx_path(mvm, queues, false); |
117 | } | 129 | } |
118 | 130 | ||
119 | static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) | 131 | static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) |
120 | { | 132 | { |
121 | /* | 133 | /* |
122 | * First, clear the ROC_RUNNING status bit. This will cause the TX | ||
123 | * path to drop offchannel transmissions. That would also be done | ||
124 | * by mac80211, but it is racy, in particular in the case that the | ||
125 | * time event actually completed in the firmware (which is handled | ||
126 | * in iwl_mvm_te_handle_notif). | ||
127 | */ | ||
128 | clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | ||
129 | iwl_mvm_unref(mvm, IWL_MVM_REF_ROC); | ||
130 | |||
131 | /* | ||
132 | * Of course, our status bit is just as racy as mac80211, so in | 134 | * Of course, our status bit is just as racy as mac80211, so in |
133 | * addition, fire off the work struct which will drop all frames | 135 | * addition, fire off the work struct which will drop all frames |
134 | * from the hardware queues that made it through the race. First | 136 | * from the hardware queues that made it through the race. First |
@@ -263,6 +265,60 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
263 | } | 265 | } |
264 | 266 | ||
265 | /* | 267 | /* |
268 | * Handle A Aux ROC time event | ||
269 | */ | ||
270 | static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, | ||
271 | struct iwl_time_event_notif *notif) | ||
272 | { | ||
273 | struct iwl_mvm_time_event_data *te_data, *tmp; | ||
274 | bool aux_roc_te = false; | ||
275 | |||
276 | list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) { | ||
277 | if (le32_to_cpu(notif->unique_id) == te_data->uid) { | ||
278 | aux_roc_te = true; | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | if (!aux_roc_te) /* Not a Aux ROC time event */ | ||
283 | return -EINVAL; | ||
284 | |||
285 | if (!le32_to_cpu(notif->status)) { | ||
286 | IWL_DEBUG_TE(mvm, | ||
287 | "ERROR: Aux ROC Time Event %s notification failure\n", | ||
288 | (le32_to_cpu(notif->action) & | ||
289 | TE_V2_NOTIF_HOST_EVENT_START) ? "start" : "end"); | ||
290 | return -EINVAL; | ||
291 | } | ||
292 | |||
293 | IWL_DEBUG_TE(mvm, | ||
294 | "Aux ROC time event notification - UID = 0x%x action %d\n", | ||
295 | le32_to_cpu(notif->unique_id), | ||
296 | le32_to_cpu(notif->action)); | ||
297 | |||
298 | if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) { | ||
299 | /* End TE, notify mac80211 */ | ||
300 | ieee80211_remain_on_channel_expired(mvm->hw); | ||
301 | iwl_mvm_roc_finished(mvm); /* flush aux queue */ | ||
302 | list_del(&te_data->list); /* remove from list */ | ||
303 | te_data->running = false; | ||
304 | te_data->vif = NULL; | ||
305 | te_data->uid = 0; | ||
306 | } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) { | ||
307 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | ||
308 | set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); | ||
309 | te_data->running = true; | ||
310 | ieee80211_ready_on_channel(mvm->hw); /* Start TE */ | ||
311 | } else { | ||
312 | IWL_DEBUG_TE(mvm, | ||
313 | "ERROR: Unknown Aux ROC Time Event (action = %d)\n", | ||
314 | le32_to_cpu(notif->action)); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | /* | ||
266 | * The Rx handler for time event notifications | 322 | * The Rx handler for time event notifications |
267 | */ | 323 | */ |
268 | int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | 324 | int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, |
@@ -278,10 +334,15 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | |||
278 | le32_to_cpu(notif->action)); | 334 | le32_to_cpu(notif->action)); |
279 | 335 | ||
280 | spin_lock_bh(&mvm->time_event_lock); | 336 | spin_lock_bh(&mvm->time_event_lock); |
337 | /* This time event is triggered for Aux ROC request */ | ||
338 | if (!iwl_mvm_aux_roc_te_handle_notif(mvm, notif)) | ||
339 | goto unlock; | ||
340 | |||
281 | list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) { | 341 | list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) { |
282 | if (le32_to_cpu(notif->unique_id) == te_data->uid) | 342 | if (le32_to_cpu(notif->unique_id) == te_data->uid) |
283 | iwl_mvm_te_handle_notif(mvm, te_data, notif); | 343 | iwl_mvm_te_handle_notif(mvm, te_data, notif); |
284 | } | 344 | } |
345 | unlock: | ||
285 | spin_unlock_bh(&mvm->time_event_lock); | 346 | spin_unlock_bh(&mvm->time_event_lock); |
286 | 347 | ||
287 | return 0; | 348 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 868561512783..0464599c111e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
@@ -140,9 +140,9 @@ static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) | |||
140 | 140 | ||
141 | /* TODO: move parsing to NVM code */ | 141 | /* TODO: move parsing to NVM code */ |
142 | calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; | 142 | calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; |
143 | ptat = calib[OTP_DTS_DIODE_DEVIATION]; | 143 | ptat = calib[OTP_DTS_DIODE_DEVIATION * 2]; |
144 | pa1 = calib[OTP_DTS_DIODE_DEVIATION + 1]; | 144 | pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1]; |
145 | pa2 = calib[OTP_DTS_DIODE_DEVIATION + 2]; | 145 | pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2]; |
146 | 146 | ||
147 | /* get the median: */ | 147 | /* get the median: */ |
148 | if (ptat > pa1) { | 148 | if (ptat > pa1) { |
@@ -338,10 +338,16 @@ static void check_exit_ctkill(struct work_struct *work) | |||
338 | 338 | ||
339 | duration = tt->params->ct_kill_duration; | 339 | duration = tt->params->ct_kill_duration; |
340 | 340 | ||
341 | /* make sure the device is available for direct read/writes */ | ||
342 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) | ||
343 | goto reschedule; | ||
344 | |||
341 | iwl_trans_start_hw(mvm->trans); | 345 | iwl_trans_start_hw(mvm->trans); |
342 | temp = check_nic_temperature(mvm); | 346 | temp = check_nic_temperature(mvm); |
343 | iwl_trans_stop_device(mvm->trans); | 347 | iwl_trans_stop_device(mvm->trans); |
344 | 348 | ||
349 | iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); | ||
350 | |||
345 | if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { | 351 | if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { |
346 | IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); | 352 | IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); |
347 | goto reschedule; | 353 | goto reschedule; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index e9ff38635c21..dbc870713882 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -311,6 +311,16 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) | |||
311 | return -1; | 311 | return -1; |
312 | 312 | ||
313 | /* | 313 | /* |
314 | * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used | ||
315 | * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel | ||
316 | * queue. STATION (HS2.0) uses the auxiliary context of the FW, | ||
317 | * and hence needs to be sent on the aux queue | ||
318 | */ | ||
319 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && | ||
320 | info->control.vif->type == NL80211_IFTYPE_STATION) | ||
321 | IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue; | ||
322 | |||
323 | /* | ||
314 | * If the interface on which frame is sent is the P2P_DEVICE | 324 | * If the interface on which frame is sent is the P2P_DEVICE |
315 | * or an AP/GO interface use the broadcast station associated | 325 | * or an AP/GO interface use the broadcast station associated |
316 | * with it; otherwise use the AUX station. | 326 | * with it; otherwise use the AUX station. |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5b5b0d8c6f60..06e04aaf61ee 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -67,6 +67,7 @@ | |||
67 | #include <linux/sched.h> | 67 | #include <linux/sched.h> |
68 | #include <linux/bitops.h> | 68 | #include <linux/bitops.h> |
69 | #include <linux/gfp.h> | 69 | #include <linux/gfp.h> |
70 | #include <linux/vmalloc.h> | ||
70 | 71 | ||
71 | #include "iwl-drv.h" | 72 | #include "iwl-drv.h" |
72 | #include "iwl-trans.h" | 73 | #include "iwl-trans.h" |
@@ -1773,28 +1774,207 @@ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) | |||
1773 | return cmdlen; | 1774 | return cmdlen; |
1774 | } | 1775 | } |
1775 | 1776 | ||
1776 | static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, | 1777 | static const struct { |
1777 | void *buf, u32 buflen) | 1778 | u32 start, end; |
1779 | } iwl_prph_dump_addr[] = { | ||
1780 | { .start = 0x00a00000, .end = 0x00a00000 }, | ||
1781 | { .start = 0x00a0000c, .end = 0x00a00024 }, | ||
1782 | { .start = 0x00a0002c, .end = 0x00a0003c }, | ||
1783 | { .start = 0x00a00410, .end = 0x00a00418 }, | ||
1784 | { .start = 0x00a00420, .end = 0x00a00420 }, | ||
1785 | { .start = 0x00a00428, .end = 0x00a00428 }, | ||
1786 | { .start = 0x00a00430, .end = 0x00a0043c }, | ||
1787 | { .start = 0x00a00444, .end = 0x00a00444 }, | ||
1788 | { .start = 0x00a004c0, .end = 0x00a004cc }, | ||
1789 | { .start = 0x00a004d8, .end = 0x00a004d8 }, | ||
1790 | { .start = 0x00a004e0, .end = 0x00a004f0 }, | ||
1791 | { .start = 0x00a00840, .end = 0x00a00840 }, | ||
1792 | { .start = 0x00a00850, .end = 0x00a00858 }, | ||
1793 | { .start = 0x00a01004, .end = 0x00a01008 }, | ||
1794 | { .start = 0x00a01010, .end = 0x00a01010 }, | ||
1795 | { .start = 0x00a01018, .end = 0x00a01018 }, | ||
1796 | { .start = 0x00a01024, .end = 0x00a01024 }, | ||
1797 | { .start = 0x00a0102c, .end = 0x00a01034 }, | ||
1798 | { .start = 0x00a0103c, .end = 0x00a01040 }, | ||
1799 | { .start = 0x00a01048, .end = 0x00a01094 }, | ||
1800 | { .start = 0x00a01c00, .end = 0x00a01c20 }, | ||
1801 | { .start = 0x00a01c58, .end = 0x00a01c58 }, | ||
1802 | { .start = 0x00a01c7c, .end = 0x00a01c7c }, | ||
1803 | { .start = 0x00a01c28, .end = 0x00a01c54 }, | ||
1804 | { .start = 0x00a01c5c, .end = 0x00a01c5c }, | ||
1805 | { .start = 0x00a01c84, .end = 0x00a01c84 }, | ||
1806 | { .start = 0x00a01ce0, .end = 0x00a01d0c }, | ||
1807 | { .start = 0x00a01d18, .end = 0x00a01d20 }, | ||
1808 | { .start = 0x00a01d2c, .end = 0x00a01d30 }, | ||
1809 | { .start = 0x00a01d40, .end = 0x00a01d5c }, | ||
1810 | { .start = 0x00a01d80, .end = 0x00a01d80 }, | ||
1811 | { .start = 0x00a01d98, .end = 0x00a01d98 }, | ||
1812 | { .start = 0x00a01dc0, .end = 0x00a01dfc }, | ||
1813 | { .start = 0x00a01e00, .end = 0x00a01e2c }, | ||
1814 | { .start = 0x00a01e40, .end = 0x00a01e60 }, | ||
1815 | { .start = 0x00a01e84, .end = 0x00a01e90 }, | ||
1816 | { .start = 0x00a01e9c, .end = 0x00a01ec4 }, | ||
1817 | { .start = 0x00a01ed0, .end = 0x00a01ed0 }, | ||
1818 | { .start = 0x00a01f00, .end = 0x00a01f14 }, | ||
1819 | { .start = 0x00a01f44, .end = 0x00a01f58 }, | ||
1820 | { .start = 0x00a01f80, .end = 0x00a01fa8 }, | ||
1821 | { .start = 0x00a01fb0, .end = 0x00a01fbc }, | ||
1822 | { .start = 0x00a01ff8, .end = 0x00a01ffc }, | ||
1823 | { .start = 0x00a02000, .end = 0x00a02048 }, | ||
1824 | { .start = 0x00a02068, .end = 0x00a020f0 }, | ||
1825 | { .start = 0x00a02100, .end = 0x00a02118 }, | ||
1826 | { .start = 0x00a02140, .end = 0x00a0214c }, | ||
1827 | { .start = 0x00a02168, .end = 0x00a0218c }, | ||
1828 | { .start = 0x00a021c0, .end = 0x00a021c0 }, | ||
1829 | { .start = 0x00a02400, .end = 0x00a02410 }, | ||
1830 | { .start = 0x00a02418, .end = 0x00a02420 }, | ||
1831 | { .start = 0x00a02428, .end = 0x00a0242c }, | ||
1832 | { .start = 0x00a02434, .end = 0x00a02434 }, | ||
1833 | { .start = 0x00a02440, .end = 0x00a02460 }, | ||
1834 | { .start = 0x00a02468, .end = 0x00a024b0 }, | ||
1835 | { .start = 0x00a024c8, .end = 0x00a024cc }, | ||
1836 | { .start = 0x00a02500, .end = 0x00a02504 }, | ||
1837 | { .start = 0x00a0250c, .end = 0x00a02510 }, | ||
1838 | { .start = 0x00a02540, .end = 0x00a02554 }, | ||
1839 | { .start = 0x00a02580, .end = 0x00a025f4 }, | ||
1840 | { .start = 0x00a02600, .end = 0x00a0260c }, | ||
1841 | { .start = 0x00a02648, .end = 0x00a02650 }, | ||
1842 | { .start = 0x00a02680, .end = 0x00a02680 }, | ||
1843 | { .start = 0x00a026c0, .end = 0x00a026d0 }, | ||
1844 | { .start = 0x00a02700, .end = 0x00a0270c }, | ||
1845 | { .start = 0x00a02804, .end = 0x00a02804 }, | ||
1846 | { .start = 0x00a02818, .end = 0x00a0281c }, | ||
1847 | { .start = 0x00a02c00, .end = 0x00a02db4 }, | ||
1848 | { .start = 0x00a02df4, .end = 0x00a02fb0 }, | ||
1849 | { .start = 0x00a03000, .end = 0x00a03014 }, | ||
1850 | { .start = 0x00a0301c, .end = 0x00a0302c }, | ||
1851 | { .start = 0x00a03034, .end = 0x00a03038 }, | ||
1852 | { .start = 0x00a03040, .end = 0x00a03048 }, | ||
1853 | { .start = 0x00a03060, .end = 0x00a03068 }, | ||
1854 | { .start = 0x00a03070, .end = 0x00a03074 }, | ||
1855 | { .start = 0x00a0307c, .end = 0x00a0307c }, | ||
1856 | { .start = 0x00a03080, .end = 0x00a03084 }, | ||
1857 | { .start = 0x00a0308c, .end = 0x00a03090 }, | ||
1858 | { .start = 0x00a03098, .end = 0x00a03098 }, | ||
1859 | { .start = 0x00a030a0, .end = 0x00a030a0 }, | ||
1860 | { .start = 0x00a030a8, .end = 0x00a030b4 }, | ||
1861 | { .start = 0x00a030bc, .end = 0x00a030bc }, | ||
1862 | { .start = 0x00a030c0, .end = 0x00a0312c }, | ||
1863 | { .start = 0x00a03c00, .end = 0x00a03c5c }, | ||
1864 | { .start = 0x00a04400, .end = 0x00a04454 }, | ||
1865 | { .start = 0x00a04460, .end = 0x00a04474 }, | ||
1866 | { .start = 0x00a044c0, .end = 0x00a044ec }, | ||
1867 | { .start = 0x00a04500, .end = 0x00a04504 }, | ||
1868 | { .start = 0x00a04510, .end = 0x00a04538 }, | ||
1869 | { .start = 0x00a04540, .end = 0x00a04548 }, | ||
1870 | { .start = 0x00a04560, .end = 0x00a0457c }, | ||
1871 | { .start = 0x00a04590, .end = 0x00a04598 }, | ||
1872 | { .start = 0x00a045c0, .end = 0x00a045f4 }, | ||
1873 | }; | ||
1874 | |||
1875 | static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans, | ||
1876 | struct iwl_fw_error_dump_data **data) | ||
1877 | { | ||
1878 | struct iwl_fw_error_dump_prph *prph; | ||
1879 | unsigned long flags; | ||
1880 | u32 prph_len = 0, i; | ||
1881 | |||
1882 | if (!iwl_trans_grab_nic_access(trans, false, &flags)) | ||
1883 | return 0; | ||
1884 | |||
1885 | for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { | ||
1886 | /* The range includes both boundaries */ | ||
1887 | int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - | ||
1888 | iwl_prph_dump_addr[i].start + 4; | ||
1889 | int reg; | ||
1890 | __le32 *val; | ||
1891 | |||
1892 | prph_len += sizeof(*data) + sizeof(*prph) + | ||
1893 | num_bytes_in_chunk; | ||
1894 | |||
1895 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH); | ||
1896 | (*data)->len = cpu_to_le32(sizeof(*prph) + | ||
1897 | num_bytes_in_chunk); | ||
1898 | prph = (void *)(*data)->data; | ||
1899 | prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start); | ||
1900 | val = (void *)prph->data; | ||
1901 | |||
1902 | for (reg = iwl_prph_dump_addr[i].start; | ||
1903 | reg <= iwl_prph_dump_addr[i].end; | ||
1904 | reg += 4) | ||
1905 | *val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans, | ||
1906 | reg)); | ||
1907 | *data = iwl_fw_error_next_data(*data); | ||
1908 | } | ||
1909 | |||
1910 | iwl_trans_release_nic_access(trans, &flags); | ||
1911 | |||
1912 | return prph_len; | ||
1913 | } | ||
1914 | |||
1915 | #define IWL_CSR_TO_DUMP (0x250) | ||
1916 | |||
1917 | static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans, | ||
1918 | struct iwl_fw_error_dump_data **data) | ||
1919 | { | ||
1920 | u32 csr_len = sizeof(**data) + IWL_CSR_TO_DUMP; | ||
1921 | __le32 *val; | ||
1922 | int i; | ||
1923 | |||
1924 | (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_CSR); | ||
1925 | (*data)->len = cpu_to_le32(IWL_CSR_TO_DUMP); | ||
1926 | val = (void *)(*data)->data; | ||
1927 | |||
1928 | for (i = 0; i < IWL_CSR_TO_DUMP; i += 4) | ||
1929 | *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); | ||
1930 | |||
1931 | *data = iwl_fw_error_next_data(*data); | ||
1932 | |||
1933 | return csr_len; | ||
1934 | } | ||
1935 | |||
1936 | static | ||
1937 | struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) | ||
1778 | { | 1938 | { |
1779 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1939 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
1780 | struct iwl_fw_error_dump_data *data; | 1940 | struct iwl_fw_error_dump_data *data; |
1781 | struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; | 1941 | struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; |
1782 | struct iwl_fw_error_dump_txcmd *txcmd; | 1942 | struct iwl_fw_error_dump_txcmd *txcmd; |
1943 | struct iwl_trans_dump_data *dump_data; | ||
1783 | u32 len; | 1944 | u32 len; |
1784 | int i, ptr; | 1945 | int i, ptr; |
1785 | 1946 | ||
1786 | len = sizeof(*data) + | 1947 | /* transport dump header */ |
1948 | len = sizeof(*dump_data); | ||
1949 | |||
1950 | /* host commands */ | ||
1951 | len += sizeof(*data) + | ||
1787 | cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); | 1952 | cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); |
1788 | 1953 | ||
1954 | /* CSR registers */ | ||
1955 | len += sizeof(*data) + IWL_CSR_TO_DUMP; | ||
1956 | |||
1957 | /* PRPH registers */ | ||
1958 | for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { | ||
1959 | /* The range includes both boundaries */ | ||
1960 | int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - | ||
1961 | iwl_prph_dump_addr[i].start + 4; | ||
1962 | |||
1963 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + | ||
1964 | num_bytes_in_chunk; | ||
1965 | } | ||
1966 | |||
1967 | /* FW monitor */ | ||
1789 | if (trans_pcie->fw_mon_page) | 1968 | if (trans_pcie->fw_mon_page) |
1790 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + | 1969 | len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + |
1791 | trans_pcie->fw_mon_size; | 1970 | trans_pcie->fw_mon_size; |
1792 | 1971 | ||
1793 | if (!buf) | 1972 | dump_data = vzalloc(len); |
1794 | return len; | 1973 | if (!dump_data) |
1974 | return NULL; | ||
1795 | 1975 | ||
1796 | len = 0; | 1976 | len = 0; |
1797 | data = buf; | 1977 | data = (void *)dump_data->data; |
1798 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD); | 1978 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD); |
1799 | txcmd = (void *)data->data; | 1979 | txcmd = (void *)data->data; |
1800 | spin_lock_bh(&cmdq->lock); | 1980 | spin_lock_bh(&cmdq->lock); |
@@ -1820,11 +2000,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, | |||
1820 | 2000 | ||
1821 | data->len = cpu_to_le32(len); | 2001 | data->len = cpu_to_le32(len); |
1822 | len += sizeof(*data); | 2002 | len += sizeof(*data); |
2003 | data = iwl_fw_error_next_data(data); | ||
2004 | |||
2005 | len += iwl_trans_pcie_dump_prph(trans, &data); | ||
2006 | len += iwl_trans_pcie_dump_csr(trans, &data); | ||
2007 | /* data is already pointing to the next section */ | ||
1823 | 2008 | ||
1824 | if (trans_pcie->fw_mon_page) { | 2009 | if (trans_pcie->fw_mon_page) { |
1825 | struct iwl_fw_error_dump_fw_mon *fw_mon_data; | 2010 | struct iwl_fw_error_dump_fw_mon *fw_mon_data; |
1826 | 2011 | ||
1827 | data = iwl_fw_error_next_data(data); | ||
1828 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); | 2012 | data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); |
1829 | data->len = cpu_to_le32(trans_pcie->fw_mon_size + | 2013 | data->len = cpu_to_le32(trans_pcie->fw_mon_size + |
1830 | sizeof(*fw_mon_data)); | 2014 | sizeof(*fw_mon_data)); |
@@ -1852,7 +2036,9 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, | |||
1852 | trans_pcie->fw_mon_size; | 2036 | trans_pcie->fw_mon_size; |
1853 | } | 2037 | } |
1854 | 2038 | ||
1855 | return len; | 2039 | dump_data->len = len; |
2040 | |||
2041 | return dump_data; | ||
1856 | } | 2042 | } |
1857 | #else | 2043 | #else |
1858 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | 2044 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, |